com.googlecode.jmxtrans.model.output.GraphiteWriter.java Source code

Java tutorial

Introduction

Here is the source code for com.googlecode.jmxtrans.model.output.GraphiteWriter.java

Source

/**
 * The MIT License
 * Copyright  2010 JmxTrans team
 *
 * 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 com.googlecode.jmxtrans.model.output;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableList;
import com.googlecode.jmxtrans.model.Query;
import com.googlecode.jmxtrans.model.Result;
import com.googlecode.jmxtrans.model.Server;
import com.googlecode.jmxtrans.model.ValidationException;
import com.googlecode.jmxtrans.model.naming.KeyUtils;
import com.googlecode.jmxtrans.util.OnlyOnceLogger;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.concurrent.NotThreadSafe;
import javax.inject.Inject;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import static com.google.common.base.Charsets.UTF_8;
import static com.googlecode.jmxtrans.util.NumberUtils.isValidNumber;

/**
 * This low latency and thread safe output writer sends data to a host/port combination
 * in the Graphite format.
 *
 * @see <a href="http://graphite.wikidot.com/getting-your-data-into-graphite">Getting your data into Graphite</a>
 *
 * @author jon
 */
@NotThreadSafe
@EqualsAndHashCode(exclude = "pool")
@ToString
public class GraphiteWriter extends BaseOutputWriter {
    private static final Logger log = LoggerFactory.getLogger(GraphiteWriter.class);

    private static final String DEFAULT_ROOT_PREFIX = "servers";

    private GenericKeyedObjectPool<InetSocketAddress, Socket> pool;

    private final String rootPrefix;
    private final InetSocketAddress address;

    private final OnlyOnceLogger onlyOnceLogger = new OnlyOnceLogger(log);

    @JsonCreator
    public GraphiteWriter(@JsonProperty("typeNames") ImmutableList<String> typeNames,
            @JsonProperty("booleanAsNumber") boolean booleanAsNumber, @JsonProperty("debug") Boolean debugEnabled,
            @JsonProperty("rootPrefix") String rootPrefix, @JsonProperty("host") String host,
            @JsonProperty("port") Integer port, @JsonProperty("settings") Map<String, Object> settings) {
        super(typeNames, booleanAsNumber, debugEnabled, settings);
        log.warn("GraphiteWriter is deprecated. Please use GraphiteWriterFactory instead.");
        this.rootPrefix = firstNonNull(rootPrefix, (String) getSettings().get("rootPrefix"), DEFAULT_ROOT_PREFIX);
        if (host == null) {
            host = (String) getSettings().get(HOST);
        }
        if (host == null) {
            throw new NullPointerException("Host cannot be null.");
        }
        if (port == null) {
            port = Settings.getIntegerSetting(getSettings(), PORT, null);
        }
        if (port == null) {
            throw new NullPointerException("Port cannot be null.");
        }
        this.address = new InetSocketAddress(host, port);
    }

    @Override
    public void validateSetup(Server server, Query query) throws ValidationException {
    }

    @Override
    public void internalWrite(Server server, Query query, ImmutableList<Result> results) throws Exception {
        Socket socket = null;
        PrintWriter writer = null;

        try {
            socket = pool.borrowObject(address);
            writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), UTF_8), true);

            List<String> typeNames = this.getTypeNames();

            for (Result result : results) {
                log.debug("Query result: {}", result);
                Map<String, Object> resultValues = result.getValues();
                for (Entry<String, Object> values : resultValues.entrySet()) {
                    Object value = values.getValue();
                    if (isValidNumber(value)) {

                        String line = KeyUtils.getKeyString(server, query, result, values, typeNames, rootPrefix)
                                .replaceAll("[()]", "_") + " " + value.toString() + " " + result.getEpoch() / 1000
                                + "\n";
                        log.debug("Graphite Message: {}", line);
                        writer.write(line);
                    } else {
                        onlyOnceLogger.infoOnce(
                                "Unable to submit non-numeric value to Graphite: [{}] from result [{}]", value,
                                result);
                    }
                }
            }
        } finally {
            if (writer != null && writer.checkError()) {
                log.error("Error writing to Graphite, clearing Graphite socket pool");
                pool.invalidateObject(address, socket);
            } else {
                pool.returnObject(address, socket);
            }
        }
    }

    public String getHost() {
        return address.getHostName();
    }

    public int getPort() {
        return address.getPort();
    }

    @Inject
    public void setPool(GenericKeyedObjectPool<InetSocketAddress, Socket> pool) {
        this.pool = pool;
    }

    public static Builder builder() {
        return new Builder();
    }

    public static final class Builder {
        private final ImmutableList.Builder<String> typeNames = ImmutableList.builder();
        private boolean booleanAsNumber;
        private Boolean debugEnabled;
        private String rootPrefix;
        private String host;
        private Integer port;

        private Builder() {
        }

        public Builder addTypeNames(List<String> typeNames) {
            this.typeNames.addAll(typeNames);
            return this;
        }

        public Builder addTypeName(String typeName) {
            typeNames.add(typeName);
            return this;
        }

        public Builder setBooleanAsNumber(boolean booleanAsNumber) {
            this.booleanAsNumber = booleanAsNumber;
            return this;
        }

        public Builder setDebugEnabled(boolean debugEnabled) {
            this.debugEnabled = debugEnabled;
            return this;
        }

        public Builder setRootPrefix(String rootPrefix) {
            this.rootPrefix = rootPrefix;
            return this;
        }

        public Builder setHost(String host) {
            this.host = host;
            return this;
        }

        public Builder setPort(int port) {
            this.port = port;
            return this;
        }

        public GraphiteWriter build() {
            return new GraphiteWriter(typeNames.build(), booleanAsNumber, debugEnabled, rootPrefix, host, port,
                    null);
        }
    }
}