/**
* 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.google.common.collect.ImmutableMap;
import com.googlecode.jmxtrans.exceptions.LifecycleException;
import com.googlecode.jmxtrans.model.Query;
import com.googlecode.jmxtrans.model.Result;
import com.googlecode.jmxtrans.model.Server;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import static com.google.common.base.Charsets.UTF_8;
/**
* OpenTSDBWriter which directly sends
* <p/>
* Created from sources originally written by Balazs Kossovics <bko@witbe.net>
*/
public class OpenTSDBWriter extends OpenTSDBGenericWriter {
private static final Logger log = LoggerFactory.getLogger(OpenTSDBWriter.class);
private GenericKeyedObjectPool<InetSocketAddress, Socket> pool;
private final InetSocketAddress address;
@JsonCreator
public OpenTSDBWriter(
@JsonProperty("typeNames") ImmutableList<String> typeNames,
@JsonProperty("booleanAsNumber") boolean booleanAsNumber,
@JsonProperty("debug") Boolean debugEnabled,
@JsonProperty("host") String host,
@JsonProperty("port") Integer port,
@JsonProperty("tags") Map<String, String> tags,
@JsonProperty("tagName") String tagName,
@JsonProperty("mergeTypeNamesTags") Boolean mergeTypeNamesTags,
@JsonProperty("metricNamingExpression") String metricNamingExpression,
@JsonProperty("addHostnameTag") Boolean addHostnameTag,
@JsonProperty("settings") Map<String, Object> settings) throws LifecycleException, UnknownHostException {
super(typeNames, booleanAsNumber, debugEnabled, host, port, tags, tagName, mergeTypeNamesTags, metricNamingExpression,
addHostnameTag, settings);
log.warn("OpenTSDBWriter is deprecated. Please use OpenTSDBWriterFactory instead.");
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);
}
/**
* Add the hostname tag "host" with the name of the host by default since OpenTSDB otherwise does not have this
* information.
*/
@Override
protected boolean getAddHostnameTagDefault() {
return true;
}
@Override
protected void sendOutput(String metricLine) throws IOException {
}
@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);
for (String formattedResult : messageFormatter.formatResults(results, server)) {
log.debug("OpenTSDB Message: {}", formattedResult);
writer.write("put " + formattedResult + "\n");
}
} catch (ConnectException e) {
log.error("Error while connecting to OpenTSDB", e);
} finally {
if (writer != null && writer.checkError()) {
log.error("Error writing to OpenTSDB, clearing OpenTSDB socket pool");
pool.invalidateObject(address, socket);
} else {
pool.returnObject(address, socket);
}
}
}
@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 host;
private Integer port;
private final ImmutableMap.Builder<String, String> tags = ImmutableMap.builder();
private String tagName;
private Boolean mergeTypeNamesTags;
private String metricNamingExpression;
private Boolean addHostnameTag = true;
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 setHost(String host) {
this.host = host;
return this;
}
public Builder setPort(int port) {
this.port = port;
return this;
}
public Builder addTag(String key, String value) {
this.tags.put(key, value);
return this;
}
public Builder addTags(Map<String, String> tags) {
this.tags.putAll(tags);
return this;
}
public Builder setTagName(String tagName) {
this.tagName = tagName;
return this;
}
public Builder setMergeTypeNamesTags(Boolean mergeTypeNamesTags) {
this.mergeTypeNamesTags = mergeTypeNamesTags;
return this;
}
public Builder setMetricNamingExpression(String metricNamingExpression) {
this.metricNamingExpression = metricNamingExpression;
return this;
}
public Builder setAddHostnameTag(Boolean addHostnameTag) {
this.addHostnameTag = addHostnameTag;
return this;
}
public OpenTSDBWriter build() throws LifecycleException, UnknownHostException {
return new OpenTSDBWriter(
typeNames.build(),
booleanAsNumber,
debugEnabled,
host,
port,
tags.build(),
tagName,
mergeTypeNamesTags,
metricNamingExpression,
addHostnameTag,
null
);
}
}
}