All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jmxtrans.agent.google.MetricWriter Maven / Gradle / Ivy

There is a newer version: 1.2.11
Show newest version
/*
 * Copyright (c) 2010-2013 the original author or authors
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
package org.jmxtrans.agent.google;

import org.jmxtrans.agent.util.StringUtils2;
import org.jmxtrans.agent.util.logging.Logger;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;

/**
 * @author Evgeny Minkevich
 * @author Mitch Simpson
 */
public class MetricWriter {

    private static final String[] SET_VALUES =
            new String[]{"projectid", "serviceaccount", "serviceaccountkey", "applicationcredentials", "separator", "nameprefix", "hostname"};
    private static final Set RESERVED_KEYWORDS = new HashSet(Arrays.asList(SET_VALUES));

    private final Logger logger = Logger.getLogger(this.getClass().getName());

    private SimpleDateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'");

    private String separator;
    private String namePrefix = "";

    private Map staticLabels = new LinkedHashMap<>();

    private Map metricDescriptors = new HashMap<>();
    private String cumulativePeriodStart;

    static MetricWriter getMetricWriter(@Nonnull Map settings) {
        MetricWriter writer = new MetricWriter();
        if (writer.init(settings))
            return writer;
        return null;
    }

    private boolean init(@Nonnull Map settings) {

        rfc3339.setTimeZone(TimeZone.getTimeZone("UTC"));
        cumulativePeriodStart = getNow();

        String projectId = StringUtils2.trimToEmpty(settings.get("projectId"));

        if (StringUtils2.isNullOrEmpty(projectId)) {
            logger.info("Metrics Project ID is not set. Attempting to source project id from GKE.");
            projectId = getGoogleProjectId();
        }

        if (StringUtils2.isNullOrEmpty(projectId)) {
            logger.log(Level.WARNING, "Metrics Project ID is not set. Metric Collection agent stopped.");
            return false;
        }
        logger.info("Metrics GCP Project : " + projectId);

        String applicationCredentials = StringUtils2.trimToEmpty(settings.get("applicationCredentials"));
        String serviceAccount = StringUtils2.trimToEmpty(settings.get("serviceAccount"));
        String serviceAccountKey = StringUtils2.trimToEmpty(settings.get("serviceAccountKey"));

        String separator = StringUtils2.trimToEmpty(settings.get("separator"));
        this.separator = StringUtils2.isNullOrEmpty(separator) ? ":" : separator;

        String namePrefix = StringUtils2.trimToEmpty(settings.get("namePrefix"));
        this.namePrefix = StringUtils2.isNullOrEmpty(namePrefix) ? "" : namePrefix;

        initStaticLabels(settings);

        return ApiFacade.initConnection(projectId, serviceAccount, serviceAccountKey, applicationCredentials);
    }

    private String getNow() {
        return rfc3339.format(new Date());
    }

    private void initStaticLabels(Map settings) {

        String hostname = StringUtils2.trimToEmpty(settings.get("hostname"));

        if (StringUtils2.isNullOrEmpty(hostname)) {
            hostname = System.getenv("HOSTNAME");
        }
        logger.info("Metrics HOSTNAME : " + hostname);

        this.staticLabels.put("hostname", hostname);

        for (Map.Entry entry : settings.entrySet()) {
            String value = StringUtils2.trimToEmpty(settings.get(entry.getKey()));
            if (StringUtils2.isNullOrEmpty(value) || RESERVED_KEYWORDS.contains(entry.getKey().toLowerCase().trim())) {
                continue;
            }
            this.staticLabels.put(entry.getKey(), value);
            logger.log(Level.INFO, "Static label : " + entry.getKey() + " : " + value);
        }
    }

    private String getGoogleProjectId() {
        BufferedReader in = null;
        try {
            URLConnection yc = new URL("http://metadata.google.internal/computeMetadata/v1/project/project-id")
                    .openConnection();
            yc.setRequestProperty("Metadata-Flavor", "Google");
            in = new BufferedReader(new InputStreamReader(yc.getInputStream(), "UTF-8"));
            return in.readLine();
        } catch (Exception e) {
            logger.log(Level.INFO, "Failed to source project id from GCP. Do we run in GCP? ", e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e) {
            }
        }

        return null;
    }

    public void writeQueryResult(@Nonnull String name, @Nullable String type, @Nullable Object value) {

        LinkedHashMap classificationLabels = new LinkedHashMap<>();

        classificationLabels.putAll(Collections.unmodifiableMap(staticLabels));

        String[] nameParts = name.split(this.separator);
        String metricName = nameParts[0];
        for (int i = 1; i < nameParts.length; i++) {
            classificationLabels.put("attribute_" + i, nameParts[i]);
        }

        String metricKind = metricDescriptors.get(metricName);
        if (null == metricKind) {
            metricKind = initMetricDescriptor(metricName, type, value, classificationLabels);
            metricDescriptors.put(metricName, metricKind);
        }

        if (!metricKind.equalsIgnoreCase("FAIL")) {
            writeValue(metricName, value, classificationLabels);
        }
    }

    private void writeValue(@Nonnull String metricName, @Nonnull Object value, @Nonnull Map classificationLabels) {
        String fullMetricName = this.namePrefix + metricName;
        String endTimeString = getNow();

        logger.log(Level.FINER, fullMetricName + " : " + endTimeString + " : " + value.toString() + " : " + classificationLabels.toString());

        if (metricDescriptors.get(metricName).equalsIgnoreCase("GAUGE")) {
            ApiFacade.uploadMetric(fullMetricName, endTimeString, endTimeString, value, classificationLabels);
        }

        if (metricDescriptors.get(metricName).equalsIgnoreCase("CUMULATIVE")) {
            ApiFacade.uploadMetric(fullMetricName, cumulativePeriodStart, endTimeString, value, classificationLabels);
        }
    }

    private String initMetricDescriptor(String metricName, String type, Object value, HashMap classificationLabels) {

        ArrayList labels = new ArrayList<>();
        String fullMetricName = this.namePrefix + metricName;

        String metricKind;
        String metricUnit;
        String valueType = null;

        // Selecting metric kind, metric unit and value type. Format (assuming ':' is a separator):
        // [ KIND [: UNIT [: VALUE TYPE ]]]
        if (!StringUtils2.isNullOrEmpty(type)) {
            String[] typeParts = type.split(this.separator);
            metricKind = typeParts[0];
            if (typeParts.length > 1) {
                metricUnit = typeParts[1];
            } else {
                metricUnit = "1";
            }
            if (typeParts.length > 2) {
                valueType = typeParts[2];
            }
        } else {
            metricKind = "GAUGE";
            metricUnit = "1";
        }

        if (null == valueType) {
            valueType = selectValueType(value);
        }

        for (Map.Entry entry : classificationLabels.entrySet()) {
            String key = entry.getKey();
            labels.add(key);
        }

        return ApiFacade.initCustomMetricDescriptor(
                fullMetricName,
                metricKind,
                metricUnit,
                valueType,
                labels);
    }

    private static String selectValueType(Object value) {
        if (value instanceof Double || value instanceof Float) {
            return "DOUBLE";
        }
        if (value instanceof Long || value instanceof Integer) {
            return "INT64";
        }
        if (value instanceof Boolean) {
            return "BOOL";
        }
        return "STRING";
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy