mirror of
https://github.com/NationalSecurityAgency/timely.git
synced 2026-11-10 11:51:29 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70672972b2 | ||
|
|
276e5e8fb2 | ||
|
|
673ae360e8 | ||
|
|
bb3386925c | ||
|
|
ecf481440c | ||
|
|
7582b62391 | ||
|
|
97edb406bc | ||
|
|
86a5e58683 | ||
|
|
4e8a7dbfb2 | ||
|
|
03f11ca11c | ||
|
|
849e265536 | ||
|
|
6d83aa98cd | ||
|
|
00b36ed7b8 | ||
|
|
f19779ce13 | ||
|
|
fe7daa3faa | ||
|
|
739d3a4726 | ||
|
|
d7b747ef79 | ||
|
|
0f891b28b2 | ||
|
|
ca86bddba1 | ||
|
|
6e9ab8e533 | ||
|
|
6c52ee5715 | ||
|
|
52ebc1856a | ||
|
|
ac390d5bed | ||
|
|
80fd98d304 | ||
|
|
6467283cbb | ||
|
|
cdc277067a | ||
|
|
c27a3d2bb6 | ||
|
|
3498c5e546 | ||
|
|
01ecbce346 | ||
|
|
1e746df912 | ||
|
|
d9214ed406 | ||
|
|
9a1c0e6e2f | ||
|
|
95f3e3d596 | ||
|
|
aaa0d91f11 | ||
|
|
48509e747b | ||
|
|
286bb85cab | ||
|
|
abfebeca60 | ||
|
|
e335eeb3b4 | ||
|
|
12d3695f10 | ||
|
|
61df23e6ba | ||
|
|
2640cbaf80 | ||
|
|
11a417c890 | ||
|
|
780e8f37b8 | ||
|
|
5ce377b15c | ||
|
|
4ed6eb98de | ||
|
|
4d08db3fbc | ||
|
|
16d73a1845 | ||
|
|
42b06cf60c | ||
|
|
e772728159 | ||
|
|
ebce93684a | ||
|
|
ff7a75c7c4 | ||
|
|
ad61f2cc85 | ||
|
|
e8beb77cb9 | ||
|
|
d6839fbc6c | ||
|
|
d53079a996 | ||
|
|
2e7489afef | ||
|
|
ee71a2c74f |
No files matched your search
@@ -8,4 +8,5 @@ logs/
|
||||
server/pki/
|
||||
client/src/main/python/setup.py
|
||||
grafana/timely-app/yarn-error.log
|
||||
grafana/timely-app/data/
|
||||
|
||||
+1
-19
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>2.1.4-SNAPSHOT</version>
|
||||
<version>2.2.3</version>
|
||||
</parent>
|
||||
<artifactId>timely-analytics</artifactId>
|
||||
<!--
|
||||
@@ -64,24 +64,6 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerId>jdt</compilerId>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-jdt</artifactId>
|
||||
<version>1.4.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ $(uname) == "Darwin" ]]; then
|
||||
THIS_SCRIPT=$(python -c 'import os,sys; print os.path.realpath(sys.argv[1])' "$0")
|
||||
THIS_SCRIPT=$(python -c 'import os,sys; print os.path.realpath(sys.argv[1])' "$0")
|
||||
else
|
||||
THIS_SCRIPT=$(readlink -f "$0")
|
||||
HW=`uname -m`
|
||||
OS_PATH=linux-${HW}
|
||||
THIS_SCRIPT=$(readlink -f "$0")
|
||||
HW=`uname -m`
|
||||
OS_PATH=linux-${HW}
|
||||
fi
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
export INSTANCE="1"
|
||||
export INSTANCE="1"
|
||||
else
|
||||
export INSTANCE="$1"
|
||||
export INSTANCE="$1"
|
||||
fi
|
||||
|
||||
PID=$(jps -m | grep -E 'timely-balancer-.*-exec.jar' | grep "instance=${INSTANCE}" | awk '{print $1}')
|
||||
@@ -19,7 +19,6 @@ PID=$(jps -m | grep -E 'timely-balancer-.*-exec.jar' | grep "instance=${INSTANCE
|
||||
if [ "$PID" == "" ]; then
|
||||
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||
BASE_DIR=$(cd "$THIS_DIR"/.. && pwd)
|
||||
TMP_DIR="${BASE_DIR}/tmp"
|
||||
LIB_DIR="${BASE_DIR}/lib"
|
||||
BIN_DIR="${BASE_DIR}/bin"
|
||||
export CONF_DIR="${BASE_DIR}/conf"
|
||||
@@ -32,18 +31,12 @@ if [ "$PID" == "" ]; then
|
||||
# use either a value from timely-balancer-env.sh or the default
|
||||
export LOG_DIR="${TIMELY_LOG_DIR:-${BASE_DIR}/logs}"
|
||||
|
||||
if [[ -e ${TMP_DIR} ]]; then
|
||||
rm -rf "${TMP_DIR}"
|
||||
if [[ ! -e ${NATIVE_DIR} ]]; then
|
||||
mkdir -p "${NATIVE_DIR}"
|
||||
fi
|
||||
mkdir "${TMP_DIR}"
|
||||
|
||||
if [[ -e ${NATIVE_DIR} ]]; then
|
||||
rm -rf "${NATIVE_DIR}"
|
||||
fi
|
||||
mkdir -p "${NATIVE_DIR}"
|
||||
|
||||
if [[ ! -e ${LOG_DIR} ]]; then
|
||||
mkdir "${LOG_DIR}"
|
||||
mkdir "${LOG_DIR}"
|
||||
fi
|
||||
|
||||
JVM_ARGS="-Xmx2G -Xms2G -XX:NewSize=1G -XX:MaxNewSize=1G"
|
||||
@@ -53,12 +46,15 @@ if [ "$PID" == "" ]; then
|
||||
JVM_ARGS="${JVM_ARGS} -Djava.net.preferIPv4Stack=true"
|
||||
JVM_ARGS="${JVM_ARGS} -XX:+UseNUMA"
|
||||
|
||||
# for linux varieties of OS, extract native libraries if not already present
|
||||
if [[ -n "$OS_PATH" ]]; then
|
||||
pushd "${BASE_DIR}/bin" || exit
|
||||
"${JAVA_HOME}"/bin/jar xf "${LIB_DIR}"/netty-tcnative-boringssl-static-*.Final-"${OS_PATH}".jar ${NATIVE_DIR}/libnetty_tcnative_linux_"${HW}".so
|
||||
"${JAVA_HOME}"/bin/jar xf "${LIB_DIR}"/netty-transport-native-epoll-*-"${OS_PATH}".jar ${NATIVE_DIR}/libnetty_transport_native_epoll_"${HW}".so
|
||||
popd || exit
|
||||
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
||||
if [[ ! -d ${NATIVE_DIR} || -z "$(ls -A ${NATIVE_DIR})" ]]; then
|
||||
pushd "${BASE_DIR}/bin" || exit
|
||||
"${JAVA_HOME}"/bin/jar xf "${LIB_DIR}"/netty-tcnative-boringssl-static-*.Final-"${OS_PATH}".jar META-INF/native/libnetty_tcnative_linux_"${HW}".so
|
||||
"${JAVA_HOME}"/bin/jar xf "${LIB_DIR}"/netty-transport-native-epoll-*-"${OS_PATH}".jar META-INF/native/libnetty_transport_native_epoll_"${HW}".so
|
||||
popd || exit
|
||||
fi
|
||||
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
||||
fi
|
||||
|
||||
echo "${JAVA_HOME}/bin/java ${JVM_ARGS} -jar ${BIN_DIR}/timely-balancer-*-exec.jar --instance=${INSTANCE}"
|
||||
|
||||
@@ -48,40 +48,47 @@ timely:
|
||||
server:
|
||||
ip: ${HOST_IP}
|
||||
tcp-base-port: ${TCP_BASE_PORT}
|
||||
num-tcp-pools: 1
|
||||
tcp-buffer-size: 100
|
||||
tcp-client-pool:
|
||||
min-idle-per-key: 0
|
||||
max-idle-per-key: 40
|
||||
max-total-per-key: 40
|
||||
min-idle-per-key: 5
|
||||
max-idle-per-key: 5
|
||||
max-total-per-key: 5
|
||||
max-total: -1
|
||||
lifo: true
|
||||
fairness: false
|
||||
max-wait-millis: -1
|
||||
min-evictable-idle-time-millis: 1800000
|
||||
lifo: false
|
||||
fairness: true
|
||||
max-wait-millis: 60000
|
||||
min-evictable-idle-time-millis: -1
|
||||
evictor-shutdown-timeout-millis: 10000
|
||||
soft-min-evictable-idle-time-millis: -1
|
||||
soft-min-evictable-idle-time-millis: 300000
|
||||
num-tests-per-eviction-run: 3
|
||||
time-between-eviction-runs-millis: -1
|
||||
time-between-eviction-runs-millis: 30000
|
||||
block-when-exhausted: true
|
||||
remove-abandoned-on-borrow: false
|
||||
remove-abandoned-on-maintenance: true
|
||||
remove-abandoned-timeout-millis: 600000
|
||||
remove-abandoned-logging: true
|
||||
jmx-enabled: true
|
||||
test-on-borrow: false
|
||||
test-on-return: false
|
||||
udp-base-port: ${UDP_BASE_PORT}
|
||||
udp-client-pool:
|
||||
min-idle-per-key: 0
|
||||
max-idle-per-key: 40
|
||||
max-total-per-key: 40
|
||||
min-idle-per-key: 5
|
||||
max-idle-per-key: 5
|
||||
max-total-per-key: 5
|
||||
max-total: -1
|
||||
lifo: true
|
||||
fairness: false
|
||||
max-wait-millis: -1
|
||||
min-evictable-idle-time-millis: 1800000
|
||||
lifo: false
|
||||
fairness: true
|
||||
max-wait-millis: 60000
|
||||
min-evictable-idle-time-millis: -1
|
||||
evictor-shutdown-timeout-millis: 10000
|
||||
soft-min-evictable-idle-time-millis: -1
|
||||
soft-min-evictable-idle-time-millis: 300000
|
||||
num-tests-per-eviction-run: 3
|
||||
time-between-eviction-runs-millis: -1
|
||||
time-between-eviction-runs-millis: 30000
|
||||
block-when-exhausted: true
|
||||
remove-abandoned-on-borrow: false
|
||||
remove-abandoned-on-maintenance: true
|
||||
remove-abandoned-timeout-millis: 600000
|
||||
remove-abandoned-logging: true
|
||||
jmx-enabled: true
|
||||
test-on-borrow: false
|
||||
test-on-return: false
|
||||
@@ -91,6 +98,10 @@ timely:
|
||||
base-port: ${HTTP_BASE_PORT}
|
||||
redirect-path: /secure-me
|
||||
strict-transport-max-age: 604800
|
||||
connection-request-timeout: 5000
|
||||
connect-timeout: 5000
|
||||
socketTimeout: 300000
|
||||
request-timeout: 300000
|
||||
cors:
|
||||
allow-any-origin: false
|
||||
allow-null-origin: false
|
||||
@@ -99,19 +110,23 @@ timely:
|
||||
allowed-methods: DELETE,GET,HEAD,OPTIONS,PUT,POST
|
||||
allowed-headers: content-type
|
||||
httpClientPool:
|
||||
min-idle-per-key: 0
|
||||
min-idle-per-key: 10
|
||||
max-idle-per-key: 40
|
||||
max-total-per-key: 40
|
||||
max-total: -1
|
||||
lifo: true
|
||||
fairness: false
|
||||
max-wait-millis: -1
|
||||
min-evictable-idle-time-millis: 1800000
|
||||
lifo: false
|
||||
fairness: true
|
||||
max-wait-millis: 60000
|
||||
min-evictable-idle-time-millis: -1
|
||||
evictor-shutdown-timeout-millis: 10000
|
||||
soft-min-evictable-idle-time-millis: -1
|
||||
soft-min-evictable-idle-time-millis: 300000
|
||||
num-tests-per-eviction-run: 3
|
||||
time-between-eviction-runs-millis: -1
|
||||
time-between-eviction-runs-millis: 30000
|
||||
block-when-exhausted: true
|
||||
remove-abandoned-on-borrow: false
|
||||
remove-abandoned-on-maintenance: true
|
||||
remove-abandoned-timeout-millis: 600000
|
||||
remove-abandoned-logging: true
|
||||
jmx-enabled: true
|
||||
test-on-borrow: false
|
||||
test-on-return: false
|
||||
@@ -130,15 +145,19 @@ timely:
|
||||
max-idle-per-key: 40
|
||||
max-total-per-key: 40
|
||||
max-total: -1
|
||||
lifo: true
|
||||
fairness: false
|
||||
max-wait-millis: -1
|
||||
min-evictable-idle-time-millis: 1800000
|
||||
lifo: false
|
||||
fairness: true
|
||||
max-wait-millis: 60000
|
||||
min-evictable-idle-time-millis: -1
|
||||
evictor-shutdown-timeout-millis: 10000
|
||||
soft-min-evictable-idle-time-millis: -1
|
||||
soft-min-evictable-idle-time-millis: 300000
|
||||
num-tests-per-eviction-run: 3
|
||||
time-between-eviction-runs-millis: -1
|
||||
time-between-eviction-runs-millis: 30000
|
||||
block-when-exhausted: true
|
||||
remove-abandoned-on-borrow: false
|
||||
remove-abandoned-on-maintenance: true
|
||||
remove-abandoned-timeout-millis: 600000
|
||||
remove-abandoned-logging: true
|
||||
jmx-enabled: true
|
||||
test-on-borrow: false
|
||||
test-on-return: false
|
||||
|
||||
+5
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>2.1.4-SNAPSHOT</version>
|
||||
<version>2.2.3</version>
|
||||
</parent>
|
||||
<artifactId>timely-balancer</artifactId>
|
||||
<description>Timely Balancer</description>
|
||||
@@ -44,6 +44,10 @@
|
||||
<groupId>io.github.classgraph</groupId>
|
||||
<artifactId>classgraph</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport-classes-epoll</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.javacsv</groupId>
|
||||
<artifactId>javacsv</artifactId>
|
||||
|
||||
Vendored
-7
@@ -46,12 +46,5 @@
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/src/main/resources/webapp</directory>
|
||||
<outputDirectory>bin/webapp</outputDirectory>
|
||||
<includes>
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -83,8 +83,10 @@ import timely.common.configuration.SecurityProperties;
|
||||
import timely.common.configuration.SslClientProperties;
|
||||
import timely.common.configuration.SslServerProperties;
|
||||
import timely.common.configuration.ZookeeperProperties;
|
||||
import timely.netty.http.HttpStaticFileServerHandler;
|
||||
import timely.netty.http.NonSslRedirectHandler;
|
||||
import timely.netty.http.HttpStrictTransportSecurityHandler;
|
||||
import timely.netty.http.HttpVersionRequestHandler;
|
||||
import timely.netty.http.NonSslForbiddenHandler;
|
||||
import timely.netty.http.NotFoundHandler;
|
||||
import timely.netty.http.TimelyExceptionHandler;
|
||||
import timely.netty.http.auth.X509LoginRequestHandler;
|
||||
import timely.netty.tcp.MetricsBufferDecoder;
|
||||
@@ -217,16 +219,12 @@ public class Balancer {
|
||||
}
|
||||
log.info("Using channel class {}", channelClass.getSimpleName());
|
||||
|
||||
List<TcpClientPool> tcpClientPools = new ArrayList<>();
|
||||
for (int x = 0; x < balancerServerProperties.getNumTcpPools(); x++) {
|
||||
tcpClientPools.add(new TcpClientPool(balancerServerProperties));
|
||||
}
|
||||
|
||||
final ServerBootstrap tcpServer = new ServerBootstrap();
|
||||
tcpServer.group(tcpBossGroup, tcpWorkerGroup);
|
||||
tcpServer.channel(channelClass);
|
||||
tcpServer.handler(new LoggingHandler());
|
||||
tcpServer.childHandler(setupTcpChannel(metricResolver, tcpClientPools));
|
||||
TcpClientPool tcpClientPool = new TcpClientPool(balancerServerProperties);
|
||||
tcpServer.childHandler(setupTcpChannel(metricResolver, tcpClientPool));
|
||||
tcpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||
tcpServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||
tcpServer.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
@@ -421,8 +419,9 @@ public class Balancer {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) {
|
||||
|
||||
ch.pipeline().addLast("ssl", new NonSslRedirectHandler(balancerHttpProperties, sslCtx));
|
||||
ch.pipeline().addLast("nonsslforbidden", new NonSslForbiddenHandler(balancerHttpProperties, sslCtx));
|
||||
ch.pipeline().addLast("encoder", new HttpResponseEncoder());
|
||||
ch.pipeline().addLast("strict", new HttpStrictTransportSecurityHandler(balancerHttpProperties));
|
||||
ch.pipeline().addLast("decoder", new HttpRequestDecoder(4096, 32768, 8192, true, 128));
|
||||
ch.pipeline().addLast("compressor", new HttpContentCompressor());
|
||||
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
|
||||
@@ -430,10 +429,10 @@ public class Balancer {
|
||||
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
|
||||
ch.pipeline().addLast("queryDecoder",
|
||||
new timely.netty.http.HttpRequestDecoder(authenticationService, securityProperties, balancerHttpProperties));
|
||||
ch.pipeline().addLast("fileServer",
|
||||
new HttpStaticFileServerHandler().setIgnoreSslHandshakeErrors(sslServerProperties.isIgnoreSslHandshakeErrors()));
|
||||
ch.pipeline().addLast("notfound", new NotFoundHandler());
|
||||
ch.pipeline().addLast("login", new X509LoginRequestHandler(authenticationService, securityProperties, balancerHttpProperties));
|
||||
ch.pipeline().addLast("httpRelay", new HttpRelayHandler(metricResolver, httpClientPool));
|
||||
ch.pipeline().addLast("version", new HttpVersionRequestHandler());
|
||||
ch.pipeline().addLast("httpRelay", new HttpRelayHandler(balancerHttpProperties, metricResolver, httpClientPool));
|
||||
ch.pipeline().addLast("error", new TimelyExceptionHandler().setIgnoreSslHandshakeErrors(sslServerProperties.isIgnoreSslHandshakeErrors()));
|
||||
}
|
||||
};
|
||||
@@ -454,7 +453,7 @@ public class Balancer {
|
||||
};
|
||||
}
|
||||
|
||||
protected ChannelHandler setupTcpChannel(MetricResolver metricResolver, List<TcpClientPool> tcpClientPools) {
|
||||
protected ChannelHandler setupTcpChannel(MetricResolver metricResolver, TcpClientPool tcpClientPool) {
|
||||
return new ChannelInitializer<SocketChannel>() {
|
||||
|
||||
@Override
|
||||
@@ -462,7 +461,7 @@ public class Balancer {
|
||||
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
|
||||
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(65536, true, Delimiters.lineDelimiter()));
|
||||
ch.pipeline().addLast("putDecoder", new TcpDecoder());
|
||||
ch.pipeline().addLast("tcpRelayHandler", new TcpRelayHandler(metricResolver, tcpClientPools));
|
||||
ch.pipeline().addLast("tcpRelayHandler", new TcpRelayHandler(metricResolver, tcpClientPool));
|
||||
ch.pipeline().addLast("versionHandler", new TcpVersionHandler());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -91,17 +91,21 @@ public class MetricResolver {
|
||||
final protected BalancerProperties balancerProperties;
|
||||
final protected CacheProperties cacheProperties;
|
||||
final protected HealthChecker healthChecker;
|
||||
final protected Path assignmentFile;
|
||||
final protected FileSystem fs;
|
||||
|
||||
private enum BalanceType {
|
||||
HIGH_LOW, HIGH_AVG, AVG_LOW
|
||||
}
|
||||
|
||||
public MetricResolver(CuratorFramework curatorFramework, BalancerProperties balancerProperties, CacheProperties cacheProperties,
|
||||
HealthChecker healthChecker) {
|
||||
HealthChecker healthChecker) throws Exception {
|
||||
this.curatorFramework = curatorFramework;
|
||||
this.balancerProperties = balancerProperties;
|
||||
this.cacheProperties = cacheProperties;
|
||||
this.healthChecker = healthChecker;
|
||||
this.assignmentFile = new Path(balancerProperties.getAssignmentFile());
|
||||
this.fs = getFileSystem(this.assignmentFile);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
@@ -916,10 +920,8 @@ public class MetricResolver {
|
||||
|
||||
protected void createAssignmentFile() {
|
||||
try {
|
||||
log.info("Creating assignment file: " + balancerProperties.getAssignmentFile());
|
||||
Path assignmentFile = new Path(balancerProperties.getAssignmentFile());
|
||||
FileSystem fs = getFileSystem(assignmentFile);
|
||||
fs.create(assignmentFile);
|
||||
log.info("Creating assignment file: " + this.assignmentFile);
|
||||
this.fs.create(this.assignmentFile);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
@@ -927,9 +929,7 @@ public class MetricResolver {
|
||||
|
||||
protected long getLastWrittenToHdfsTimestamp() {
|
||||
try {
|
||||
Path assignmentFile = new Path(balancerProperties.getAssignmentFile());
|
||||
FileSystem fs = getFileSystem(assignmentFile);
|
||||
FileStatus fileStatus = fs.getFileStatus(assignmentFile);
|
||||
FileStatus fileStatus = this.fs.getFileStatus(this.assignmentFile);
|
||||
return fileStatus.getModificationTime();
|
||||
} catch (FileNotFoundException e) {
|
||||
createAssignmentFile();
|
||||
@@ -960,16 +960,15 @@ public class MetricResolver {
|
||||
// proceed with reading from HDFS
|
||||
|
||||
Map<String,TimelyBalancedHost> assignedMetricToHostMap = new TreeMap<>();
|
||||
CsvReader reader = null;
|
||||
try {
|
||||
boolean acquired = false;
|
||||
while (!acquired) {
|
||||
acquired = assignmentsIPRWLock.readLock().acquire(60, TimeUnit.SECONDS);
|
||||
}
|
||||
balancerLock.writeLock().lock();
|
||||
Path assignmentFile = new Path(balancerProperties.getAssignmentFile());
|
||||
FileSystem fs = getFileSystem(assignmentFile);
|
||||
FSDataInputStream iStream = fs.open(assignmentFile);
|
||||
CsvReader reader = new CsvReader(iStream, ',', Charset.forName("UTF-8"));
|
||||
FSDataInputStream iStream = this.fs.open(this.assignmentFile);
|
||||
reader = new CsvReader(iStream, ',', Charset.forName("UTF-8"));
|
||||
reader.setUseTextQualifier(false);
|
||||
|
||||
// skip the headers
|
||||
@@ -1031,6 +1030,9 @@ public class MetricResolver {
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
balancerLock.writeLock().unlock();
|
||||
try {
|
||||
assignmentsIPRWLock.readLock().release();
|
||||
@@ -1052,12 +1054,10 @@ public class MetricResolver {
|
||||
nonCachedMetricsLocalLock.readLock().lock();
|
||||
try {
|
||||
if (!metricToHostMap.isEmpty()) {
|
||||
Path assignmentFile = new Path(balancerProperties.getAssignmentFile());
|
||||
FileSystem fs = getFileSystem(assignmentFile);
|
||||
if (!fs.exists(assignmentFile.getParent())) {
|
||||
fs.mkdirs(assignmentFile.getParent());
|
||||
if (!this.fs.exists(this.assignmentFile.getParent())) {
|
||||
this.fs.mkdirs(this.assignmentFile.getParent());
|
||||
}
|
||||
FSDataOutputStream oStream = fs.create(assignmentFile, true);
|
||||
FSDataOutputStream oStream = this.fs.create(this.assignmentFile, true);
|
||||
writer = new CsvWriter(oStream, ',', Charset.forName("UTF-8"));
|
||||
writer.setUseTextQualifier(false);
|
||||
writer.write("metric");
|
||||
@@ -1080,7 +1080,7 @@ public class MetricResolver {
|
||||
if (!assignmentsLastUpdatedInHdfs.get().succeeded()) {
|
||||
assignmentsLastUpdatedInHdfs.forceSet(now);
|
||||
}
|
||||
log.debug("Wrote {} assignments to hdfs lastHdfsUpdate = lastLocalUpdate ({})", metricToHostMap.size(),
|
||||
log.info("Wrote {} assignments to hdfs lastHdfsUpdate = lastLocalUpdate ({})", metricToHostMap.size(),
|
||||
new Date(assignmentsLastUpdatedLocal.get()));
|
||||
// remove metric from metricMap (ArrivalRate) if not being cached
|
||||
metricMap.entrySet().removeIf(e -> !metricToHostMap.containsKey(e.getKey()));
|
||||
|
||||
@@ -50,7 +50,7 @@ public class BalancerConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MetricResolver metricResolver(CuratorFramework curatorFramework, BalancerProperties balancerProperties, CacheProperties cacheProperties,
|
||||
HealthChecker healthChecker) {
|
||||
HealthChecker healthChecker) throws Exception {
|
||||
MetricResolver metricResolver = new MetricResolver(curatorFramework, balancerProperties, cacheProperties, healthChecker);
|
||||
metricResolver.start();
|
||||
return metricResolver;
|
||||
|
||||
@@ -2,7 +2,6 @@ package timely.balancer.configuration;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
@@ -14,11 +13,48 @@ import timely.common.configuration.HttpProperties;
|
||||
@ConfigurationProperties(prefix = "timely.balancer.http")
|
||||
public class BalancerHttpProperties extends HttpProperties {
|
||||
|
||||
private int connectionRequestTimeout = 5000;
|
||||
private int connectTimeout = 5000;
|
||||
private int socketTimeout = 300000;
|
||||
private int requestTimeout = 300000;
|
||||
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private GenericKeyedObjectPoolConfig<CloseableHttpClient> httpClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||
private GenericKeyedObjectPoolConfiguration<CloseableHttpClient> httpClientPool = new GenericKeyedObjectPoolConfiguration<>();
|
||||
|
||||
public GenericKeyedObjectPoolConfig<CloseableHttpClient> getHttpClientPool() {
|
||||
public GenericKeyedObjectPoolConfiguration<CloseableHttpClient> getHttpClientPool() {
|
||||
return httpClientPool;
|
||||
}
|
||||
|
||||
public void setConnectionRequestTimeout(final int connectionRequestTimeout) {
|
||||
this.connectionRequestTimeout = connectionRequestTimeout;
|
||||
}
|
||||
|
||||
public int getConnectionRequestTimeout() {
|
||||
return connectionRequestTimeout;
|
||||
}
|
||||
|
||||
public void setConnectTimeout(final int connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
public int getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public void setSocketTimeout(final int socketTimeout) {
|
||||
this.socketTimeout = socketTimeout;
|
||||
}
|
||||
|
||||
public int getSocketTimeout() {
|
||||
return socketTimeout;
|
||||
}
|
||||
|
||||
public void setRequestTimeout(int requestTimeout) {
|
||||
this.requestTimeout = requestTimeout;
|
||||
}
|
||||
|
||||
public int getRequestTimeout() {
|
||||
return requestTimeout;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package timely.balancer.configuration;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
@@ -17,32 +16,22 @@ public class BalancerServerProperties extends ServerProperties {
|
||||
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private GenericKeyedObjectPoolConfig<UdpClient> udpClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||
private GenericKeyedObjectPoolConfiguration<UdpClient> udpClientPool = new GenericKeyedObjectPoolConfiguration<>();
|
||||
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private GenericKeyedObjectPoolConfig<TcpClient> tcpClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||
|
||||
private int numTcpPools = 1;
|
||||
private GenericKeyedObjectPoolConfiguration<TcpClient> tcpClientPool = new GenericKeyedObjectPoolConfiguration<>();
|
||||
|
||||
private int tcpBufferSize = -1;
|
||||
|
||||
public GenericKeyedObjectPoolConfig<UdpClient> getUdpClientPool() {
|
||||
public GenericKeyedObjectPoolConfiguration<UdpClient> getUdpClientPool() {
|
||||
return udpClientPool;
|
||||
}
|
||||
|
||||
public GenericKeyedObjectPoolConfig<TcpClient> getTcpClientPool() {
|
||||
public GenericKeyedObjectPoolConfiguration<TcpClient> getTcpClientPool() {
|
||||
return tcpClientPool;
|
||||
}
|
||||
|
||||
public int getNumTcpPools() {
|
||||
return numTcpPools;
|
||||
}
|
||||
|
||||
public void setNumTcpPools(int numTcpPools) {
|
||||
this.numTcpPools = numTcpPools;
|
||||
}
|
||||
|
||||
public int getTcpBufferSize() {
|
||||
return tcpBufferSize;
|
||||
}
|
||||
|
||||
+2
-3
@@ -2,7 +2,6 @@ package timely.balancer.configuration;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
@@ -16,9 +15,9 @@ public class BalancerWebsocketProperties extends WebsocketProperties {
|
||||
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private GenericKeyedObjectPoolConfig<WebSocketSubscriptionClient> wsClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||
private GenericKeyedObjectPoolConfiguration<WebSocketSubscriptionClient> wsClientPool = new GenericKeyedObjectPoolConfiguration<>();
|
||||
|
||||
public GenericKeyedObjectPoolConfig<WebSocketSubscriptionClient> getWsClientPool() {
|
||||
public GenericKeyedObjectPoolConfiguration<WebSocketSubscriptionClient> getWsClientPool() {
|
||||
return wsClientPool;
|
||||
}
|
||||
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package timely.balancer.configuration;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.apache.commons.pool2.impl.AbandonedConfig;
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
|
||||
public class GenericKeyedObjectPoolConfiguration<T> extends GenericKeyedObjectPoolConfig<T> {
|
||||
|
||||
private Duration removeAbandonedTimeout = null;
|
||||
private boolean removeAbandonedLogging = false;
|
||||
private boolean removeAbandonedOnBorrow = false;
|
||||
private boolean removeAbandonedOnMaintenance = false;
|
||||
|
||||
public void setMaxWaitMillis(long maxWaitMillis) {
|
||||
super.setMaxWait(Duration.ofMillis(maxWaitMillis));
|
||||
}
|
||||
|
||||
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
|
||||
super.setMinEvictableIdleTime(Duration.ofMillis(minEvictableIdleTimeMillis));
|
||||
}
|
||||
|
||||
public void setEvictorShutdownTimeoutMillis(long evictorShutdownTimeoutMillis) {
|
||||
super.setEvictorShutdownTimeout(Duration.ofMillis(evictorShutdownTimeoutMillis));
|
||||
}
|
||||
|
||||
public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) {
|
||||
super.setSoftMinEvictableIdleTime(Duration.ofMillis(softMinEvictableIdleTimeMillis));
|
||||
}
|
||||
|
||||
public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
|
||||
super.setTimeBetweenEvictionRuns(Duration.ofMillis(timeBetweenEvictionRunsMillis));
|
||||
}
|
||||
|
||||
public void setRemoveAbandonedTimeoutMillis(long removeAbandonedTimeoutMillis) {
|
||||
this.removeAbandonedTimeout = Duration.ofMillis(removeAbandonedTimeoutMillis);
|
||||
}
|
||||
|
||||
public Duration getRemoveAbandonedTimeout() {
|
||||
return removeAbandonedTimeout;
|
||||
}
|
||||
|
||||
public void setRemoveAbandonedOnBorrow(boolean removeAbandonedOnBorrow) {
|
||||
this.removeAbandonedOnBorrow = removeAbandonedOnBorrow;
|
||||
}
|
||||
|
||||
public boolean getRemoveAbandonedOnBorrow() {
|
||||
return removeAbandonedOnBorrow;
|
||||
}
|
||||
|
||||
public void setRemoveAbandonedOnMaintenance(boolean removeAbandonedOnMaintenance) {
|
||||
this.removeAbandonedOnMaintenance = removeAbandonedOnMaintenance;
|
||||
}
|
||||
|
||||
public boolean getRemoveAbandonedOnMaintenance() {
|
||||
return removeAbandonedOnMaintenance;
|
||||
}
|
||||
|
||||
public void setRemoveAbandonedLogging(boolean removeAbandonedLogging) {
|
||||
this.removeAbandonedLogging = removeAbandonedLogging;
|
||||
}
|
||||
|
||||
public boolean getRemoveAbandonedLogging() {
|
||||
return removeAbandonedLogging;
|
||||
}
|
||||
|
||||
public AbandonedConfig getAbandonedConfig() {
|
||||
AbandonedConfig abandonedConfig = null;
|
||||
if (removeAbandonedTimeout != null) {
|
||||
abandonedConfig = new AbandonedConfig();
|
||||
abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
|
||||
if (removeAbandonedLogging) {
|
||||
abandonedConfig.setLogAbandoned(removeAbandonedLogging);
|
||||
abandonedConfig.setLogWriter(new PrintWriter(System.out, true, StandardCharsets.UTF_8));
|
||||
}
|
||||
abandonedConfig.setRemoveAbandonedOnBorrow(removeAbandonedOnBorrow);
|
||||
abandonedConfig.setRemoveAbandonedOnMaintenance(removeAbandonedOnMaintenance);
|
||||
}
|
||||
return abandonedConfig;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import timely.common.configuration.SslClientProperties;
|
||||
|
||||
public class HttpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost,CloseableHttpClient> {
|
||||
|
||||
public HttpClientPool(BalancerHttpProperties http, SSLContext sslContext, SslClientProperties sslClientProperties) {
|
||||
super(new HttpClientFactory(sslContext, sslClientProperties), http.getHttpClientPool());
|
||||
public HttpClientPool(BalancerHttpProperties config, SSLContext sslContext, SslClientProperties sslClientProperties) {
|
||||
super(new HttpClientFactory(sslContext, sslClientProperties), config.getHttpClientPool(), config.getHttpClientPool().getAbandonedConfig());
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import timely.client.tcp.TcpClient;
|
||||
|
||||
public class TcpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost,TcpClient> {
|
||||
|
||||
public TcpClientPool(BalancerServerProperties balancerServerProperties) {
|
||||
super(new TcpClientFactory(balancerServerProperties.getTcpBufferSize()), balancerServerProperties.getTcpClientPool());
|
||||
public TcpClientPool(BalancerServerProperties config) {
|
||||
super(new TcpClientFactory(config.getTcpBufferSize()), config.getTcpClientPool(), config.getTcpClientPool().getAbandonedConfig());
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import timely.client.udp.UdpClient;
|
||||
|
||||
public class UdpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost,UdpClient> {
|
||||
|
||||
public UdpClientPool(BalancerServerProperties serverProperties) {
|
||||
super(new UdpClientFactory(), serverProperties.getUdpClientPool());
|
||||
public UdpClientPool(BalancerServerProperties config) {
|
||||
super(new UdpClientFactory(), config.getUdpClientPool(), config.getUdpClientPool().getAbandonedConfig());
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,9 @@ import timely.common.configuration.SslClientProperties;
|
||||
|
||||
public class WsClientPool extends GenericKeyedObjectPool<TimelyBalancedHost,WebSocketSubscriptionClient> {
|
||||
|
||||
public WsClientPool(BalancerProperties balancerProperties, BalancerWebsocketProperties balancerWebsocketProperties, SslClientProperties sslClientProperties,
|
||||
public WsClientPool(BalancerProperties balancerProperties, BalancerWebsocketProperties config, SslClientProperties sslClientProperties,
|
||||
SSLContext sslContext) {
|
||||
super(new WsClientFactory(balancerProperties, balancerWebsocketProperties, sslClientProperties, sslContext),
|
||||
balancerWebsocketProperties.getWsClientPool());
|
||||
super(new WsClientFactory(balancerProperties, config, sslClientProperties, sslContext), config.getWsClientPool(),
|
||||
config.getWsClientPool().getAbandonedConfig());
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package timely.balancer.netty.http;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
@@ -10,12 +11,19 @@ import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
@@ -23,6 +31,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
@@ -34,7 +43,6 @@ import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import timely.api.request.AuthenticatedRequest;
|
||||
import timely.api.request.HttpRequest;
|
||||
import timely.api.request.MetricRequest;
|
||||
@@ -44,6 +52,7 @@ import timely.auth.TimelyAuthenticationToken;
|
||||
import timely.auth.util.HttpHeaderUtils;
|
||||
import timely.auth.util.ProxiedEntityUtils;
|
||||
import timely.balancer.MetricResolver;
|
||||
import timely.balancer.configuration.BalancerHttpProperties;
|
||||
import timely.balancer.connection.TimelyBalancedHost;
|
||||
import timely.balancer.connection.http.HttpClientPool;
|
||||
import timely.netty.http.TimelyHttpHandler;
|
||||
@@ -51,10 +60,13 @@ import timely.netty.http.TimelyHttpHandler;
|
||||
public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> implements TimelyHttpHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HttpRelayHandler.class);
|
||||
private BalancerHttpProperties balancerHttpProperties;
|
||||
private final HttpClientPool httpClientPool;
|
||||
private MetricResolver metricResolver;
|
||||
private ExecutorService requestExecutor = Executors.newCachedThreadPool();
|
||||
|
||||
public HttpRelayHandler(MetricResolver metricResolver, HttpClientPool httpClientPool) {
|
||||
public HttpRelayHandler(BalancerHttpProperties balancerHttpProperties, MetricResolver metricResolver, HttpClientPool httpClientPool) {
|
||||
this.balancerHttpProperties = balancerHttpProperties;
|
||||
this.metricResolver = metricResolver;
|
||||
this.httpClientPool = httpClientPool;
|
||||
}
|
||||
@@ -67,6 +79,7 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
||||
CloseableHttpResponse relayedResponse = null;
|
||||
FullHttpRequest request = null;
|
||||
try {
|
||||
String relayURI = "";
|
||||
try {
|
||||
request = msg.getHttpRequest();
|
||||
String originalURI = request.uri();
|
||||
@@ -109,45 +122,39 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
||||
}
|
||||
Header[] headerArray = new Header[relayedHeaderList.size()];
|
||||
relayedHeaderList.toArray(headerArray);
|
||||
|
||||
String relayURI = "https://" + k.getHost() + ":" + k.getHttpPort() + originalURI;
|
||||
relayURI = "https://" + k.getHost() + ":" + k.getHttpPort() + originalURI;
|
||||
HttpRequestBase relayedRequest = null;
|
||||
if (request.method().equals(HttpMethod.GET)) {
|
||||
HttpUriRequest relayedRequest = new HttpGet(relayURI);
|
||||
if (headerArray.length > 0) {
|
||||
relayedRequest.setHeaders(headerArray);
|
||||
}
|
||||
relayedResponse = client.execute(relayedRequest);
|
||||
|
||||
relayedRequest = new HttpGet(relayURI);
|
||||
} else if (request.method().equals(HttpMethod.POST)) {
|
||||
HttpPost relayedRequest = new HttpPost(relayURI);
|
||||
|
||||
relayedRequest = new HttpPost(relayURI);
|
||||
String content = request.content().toString(StandardCharsets.UTF_8);
|
||||
StringEntity entity = new StringEntity(content);
|
||||
relayedRequest.setEntity(entity);
|
||||
if (headerArray.length > 0) {
|
||||
relayedRequest.setHeaders(headerArray);
|
||||
}
|
||||
relayedResponse = client.execute(relayedRequest);
|
||||
((HttpPost) relayedRequest).setEntity(entity);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported HTTP method: " + request.method());
|
||||
}
|
||||
if (headerArray.length > 0) {
|
||||
relayedRequest.setHeaders(headerArray);
|
||||
}
|
||||
relayedResponse = executeHttpRequest(client, relayedRequest, balancerHttpProperties.getRequestTimeout());
|
||||
} catch (IOException e) {
|
||||
String message = String.format("%s calling %s", e.getMessage() == null ? "" : e.getMessage(), relayURI);
|
||||
log.error(message, e);
|
||||
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.GATEWAY_TIMEOUT.code(), e.getMessage(), e.getLocalizedMessage(), e));
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
String message = e.getMessage();
|
||||
if (message == null) {
|
||||
log.error("", e);
|
||||
if (message != null && message.contains("No matching tags")) {
|
||||
log.trace(message);
|
||||
} else {
|
||||
if (message.contains("No matching tags")) {
|
||||
log.trace(message);
|
||||
} else {
|
||||
log.error(message, e);
|
||||
}
|
||||
message = String.format("%s calling %s", e.getMessage() == null ? "" : e.getMessage(), relayURI);
|
||||
log.error(message, e);
|
||||
}
|
||||
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(), e.getMessage(), e.getLocalizedMessage(), e));
|
||||
return;
|
||||
} finally {
|
||||
if (request != null) {
|
||||
ReferenceCountUtil.release(request);
|
||||
}
|
||||
}
|
||||
FullHttpResponse response = null;
|
||||
FullHttpResponse response;
|
||||
if (relayedResponse == null) {
|
||||
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.METHOD_NOT_ALLOWED.code(), "Method not allowed", "Method not allowed"));
|
||||
} else {
|
||||
@@ -162,6 +169,8 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
||||
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
|
||||
sendResponse(ctx, response);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
if (relayedResponse != null) {
|
||||
relayedResponse.close();
|
||||
@@ -200,4 +209,22 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private CloseableHttpResponse executeHttpRequest(CloseableHttpClient httpClient, HttpRequestBase relayedRequest, long timeout) throws Exception {
|
||||
try {
|
||||
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
|
||||
requestConfigBuilder.setConnectionRequestTimeout(this.balancerHttpProperties.getConnectionRequestTimeout());
|
||||
requestConfigBuilder.setConnectTimeout(this.balancerHttpProperties.getConnectTimeout());
|
||||
requestConfigBuilder.setSocketTimeout(this.balancerHttpProperties.getSocketTimeout());
|
||||
RequestConfig requestConfig = requestConfigBuilder.build();
|
||||
relayedRequest.setConfig(requestConfig);
|
||||
Future<CloseableHttpResponse> f = requestExecutor.submit(() -> httpClient.execute(relayedRequest));
|
||||
return f.get(timeout, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
Throwable cause = Throwables.getRootCause(e);
|
||||
throw new IOException(cause.getMessage(), cause);
|
||||
} catch (Exception e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package timely.balancer.netty.tcp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.slf4j.Logger;
|
||||
@@ -27,16 +25,11 @@ public class TcpRelayHandler extends SimpleChannelInboundHandler<TcpRequest> {
|
||||
private static final String ERR_MSG = "Error storing put metric: ";
|
||||
|
||||
private MetricResolver metricResolver;
|
||||
private List<TcpClientPool> tcpClientPools;
|
||||
private TcpClientPool tcpClientPool;
|
||||
|
||||
public TcpRelayHandler(MetricResolver metricResolver, List<TcpClientPool> tcpClientPools) {
|
||||
public TcpRelayHandler(MetricResolver metricResolver, TcpClientPool tcpClientPool) {
|
||||
this.metricResolver = metricResolver;
|
||||
this.tcpClientPools = tcpClientPools;
|
||||
}
|
||||
|
||||
private TcpClientPool tcpClientPool() {
|
||||
int x = Math.toIntExact(Thread.currentThread().getId() % tcpClientPools.size());
|
||||
return tcpClientPools.get(x);
|
||||
this.tcpClientPool = tcpClientPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,15 +51,17 @@ public class TcpRelayHandler extends SimpleChannelInboundHandler<TcpRequest> {
|
||||
keyClientPair.getRight().write(line + "\n");
|
||||
} finally {
|
||||
if (keyClientPair != null && keyClientPair.getLeft() != null && keyClientPair.getRight() != null) {
|
||||
tcpClientPool().returnObject(keyClientPair.getLeft(), keyClientPair.getRight());
|
||||
tcpClientPool.returnObject(keyClientPair.getLeft(), keyClientPair.getRight());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
log.error(LOG_ERR_MSG, msg, e);
|
||||
ChannelFuture cf = ctx.writeAndFlush(Unpooled.copiedBuffer((ERR_MSG + e.getMessage() + "\n").getBytes(StandardCharsets.UTF_8)));
|
||||
if (!cf.isSuccess()) {
|
||||
log.error(Constants.ERR_WRITING_RESPONSE, cf.cause());
|
||||
Throwable t = cf.cause();
|
||||
String message = (t == null) ? "" : t.getMessage();
|
||||
log.error(String.format(Constants.ERR_WRITING_RESPONSE, message), cf.cause());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,7 +73,7 @@ public class TcpRelayHandler extends SimpleChannelInboundHandler<TcpRequest> {
|
||||
while (client == null) {
|
||||
try {
|
||||
k = (metricRequest == true) ? metricResolver.getHostPortKeyIngest(metric) : metricResolver.getHostPortKey(metric);
|
||||
client = tcpClientPool().borrowObject(k);
|
||||
client = tcpClientPool.borrowObject(k);
|
||||
} catch (Exception e1) {
|
||||
failures++;
|
||||
client = null;
|
||||
|
||||
@@ -53,7 +53,9 @@ public class UdpRelayHandler extends SimpleChannelInboundHandler<UdpRequest> {
|
||||
log.error(LOG_ERR_MSG, msg, e);
|
||||
ChannelFuture cf = ctx.writeAndFlush(Unpooled.copiedBuffer((ERR_MSG + e.getMessage() + "\n").getBytes(StandardCharsets.UTF_8)));
|
||||
if (!cf.isSuccess()) {
|
||||
log.error(Constants.ERR_WRITING_RESPONSE, cf.cause());
|
||||
Throwable t = cf.cause();
|
||||
String message = (t == null) ? "" : t.getMessage();
|
||||
log.error(String.format(Constants.ERR_WRITING_RESPONSE, message), cf.cause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class TestBalancerConfiguration {
|
||||
|
||||
@Bean
|
||||
public TestMetricResolver metricResolver(CuratorFramework curatorFramework, BalancerProperties balancerProperties, CacheProperties cacheProperties,
|
||||
HealthChecker healthChecker) {
|
||||
HealthChecker healthChecker) throws Exception {
|
||||
TestMetricResolver metricResolver = new TestMetricResolver(curatorFramework, balancerProperties, cacheProperties, healthChecker);
|
||||
metricResolver.start();
|
||||
return metricResolver;
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package timely.balancer.integration;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import timely.balancer.configuration.BalancerHttpProperties;
|
||||
import timely.netty.http.HttpStrictTransportSecurityHandler;
|
||||
import timely.test.IntegrationTest;
|
||||
import timely.test.TimelyTestRule;
|
||||
|
||||
@Category(IntegrationTest.class)
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||
public class HTTPStrictTransportSecurityIT {
|
||||
|
||||
@Autowired
|
||||
@Rule
|
||||
public TimelyTestRule testRule;
|
||||
|
||||
@Autowired
|
||||
private BalancerHttpProperties httpProperties;
|
||||
|
||||
@Autowired
|
||||
protected SSLContext clientSslContext;
|
||||
|
||||
private String baseHttpUrl;
|
||||
private String baseHttpsUrl;
|
||||
private String HSTS_HEADER_VALUE;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
baseHttpUrl = "http://" + httpProperties.getHost() + ":" + httpProperties.getPort();
|
||||
baseHttpsUrl = "https://" + httpProperties.getHost() + ":" + httpProperties.getPort();
|
||||
HSTS_HEADER_VALUE = String.format("max-age=%d; includeSubDomains; preload", httpProperties.getStrictTransportMaxAge());
|
||||
}
|
||||
|
||||
protected SSLSocketFactory getSSLSocketFactory() throws Exception {
|
||||
return clientSslContext.getSocketFactory();
|
||||
}
|
||||
|
||||
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(getSSLSocketFactory());
|
||||
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||
con.setHostnameVerifier((host, session) -> true);
|
||||
return con;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpRequest() throws Exception {
|
||||
URL url = new URL(baseHttpUrl + "/api/metrics");
|
||||
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
||||
con.setRequestMethod("GET");
|
||||
int responseCode = con.getResponseCode();
|
||||
assertEquals(403, responseCode);
|
||||
// should not have HSTS header on HTTP response
|
||||
assertNull(con.getHeaderField(HttpStrictTransportSecurityHandler.HSTS_HEADER_NAME));
|
||||
con.disconnect();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsRequestHSTS() throws Exception {
|
||||
URL url = new URL(baseHttpsUrl + "/version");
|
||||
HttpsURLConnection con = getUrlConnection(url);
|
||||
int responseCode = con.getResponseCode();
|
||||
assertEquals(200, responseCode);
|
||||
assertEquals(HSTS_HEADER_VALUE, con.getHeaderField(HttpStrictTransportSecurityHandler.HSTS_HEADER_NAME));
|
||||
con.disconnect();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsRequestNotFound() throws Exception {
|
||||
URL url = new URL(baseHttpsUrl);
|
||||
HttpsURLConnection con = getUrlConnection(url);
|
||||
int responseCode = con.getResponseCode();
|
||||
assertEquals(404, responseCode);
|
||||
assertEquals(HSTS_HEADER_VALUE, con.getHeaderField(HttpStrictTransportSecurityHandler.HSTS_HEADER_NAME));
|
||||
con.disconnect();
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public class TestMetricResolver extends MetricResolver {
|
||||
private static final Logger log = LoggerFactory.getLogger(TestMetricResolver.class);
|
||||
|
||||
public TestMetricResolver(CuratorFramework curatorFramework, BalancerProperties balancerProperties, CacheProperties cacheProperties,
|
||||
HealthChecker healthChecker) {
|
||||
HealthChecker healthChecker) throws Exception {
|
||||
super(curatorFramework, balancerProperties, cacheProperties, healthChecker);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,50 +62,61 @@ timely:
|
||||
assignment-file: file://${java.io.tmpdir}/timely/balancer/assignments.csv
|
||||
server:
|
||||
ip: 127.0.0.1
|
||||
tcp-base-port: 4242
|
||||
num-tcp-pools: 1
|
||||
tcp-base-port: 9242
|
||||
tcp-buffer-size: 100
|
||||
tcp-client-pool:
|
||||
min-idle-per-key: 0
|
||||
max-idle-per-key: 40
|
||||
max-total-per-key: 40
|
||||
min-idle-per-key: 5
|
||||
max-idle-per-key: 5
|
||||
max-total-per-key: 5
|
||||
max-total: -1
|
||||
lifo: true
|
||||
fairness: false
|
||||
max-wait-millis: -1
|
||||
min-evictable-idle-time-millis: 1800000
|
||||
lifo: false
|
||||
fairness: true
|
||||
max-wait-millis: 60000
|
||||
min-evictable-idle-time-millis: -1
|
||||
evictor-shutdown-timeout-millis: 10000
|
||||
soft-min-evictable-idle-time-millis: -1
|
||||
soft-min-evictable-idle-time-millis: 300000
|
||||
num-tests-per-eviction-run: 3
|
||||
time-between-eviction-runs-millis: -1
|
||||
time-between-eviction-runs-millis: 30000
|
||||
block-when-exhausted: true
|
||||
remove-abandoned-on-borrow: false
|
||||
remove-abandoned-on-maintenance: true
|
||||
remove-abandoned-timeout-millis: 600000
|
||||
remove-abandoned-logging: true
|
||||
jmx-enabled: true
|
||||
test-on-borrow: false
|
||||
test-on-return: false
|
||||
udp-base-port: 4245
|
||||
udp-base-port: 9245
|
||||
udp-client-pool:
|
||||
min-idle-per-key: 0
|
||||
max-idle-per-key: 40
|
||||
max-total-per-key: 40
|
||||
min-idle-per-key: 5
|
||||
max-idle-per-key: 5
|
||||
max-total-per-key: 5
|
||||
max-total: -1
|
||||
lifo: true
|
||||
fairness: false
|
||||
max-wait-millis: -1
|
||||
min-evictable-idle-time-millis: 1800000
|
||||
lifo: false
|
||||
fairness: true
|
||||
max-wait-millis: 60000
|
||||
min-evictable-idle-time-millis: -1
|
||||
evictor-shutdown-timeout-millis: 10000
|
||||
soft-min-evictable-idle-time-millis: -1
|
||||
soft-min-evictable-idle-time-millis: 300000
|
||||
num-tests-per-eviction-run: 3
|
||||
time-between-eviction-runs-millis: -1
|
||||
time-between-eviction-runs-millis: 30000
|
||||
block-when-exhausted: true
|
||||
remove-abandoned-on-borrow: false
|
||||
remove-abandoned-on-maintenance: true
|
||||
remove-abandoned-timeout-millis: 600000
|
||||
remove-abandoned-logging: true
|
||||
jmx-enabled: true
|
||||
test-on-borrow: false
|
||||
test-on-return: false
|
||||
http:
|
||||
host: localhost
|
||||
ip: 127.0.0.1
|
||||
base-port: 4243
|
||||
base-port: 9243
|
||||
redirect-path: /secure-me
|
||||
strict-transport-max-age: 604800
|
||||
connection-request-timeout: 5000
|
||||
connect-timeout: 5000
|
||||
socket-timeout: 300000
|
||||
request-timeout: 300000
|
||||
cors:
|
||||
allow-any-origin: false
|
||||
allow-null-origin: false
|
||||
@@ -114,25 +125,29 @@ timely:
|
||||
allowed-methods: DELETE,GET,HEAD,OPTIONS,PUT,POST
|
||||
allowed-headers: content-type
|
||||
http-client-pool:
|
||||
min-idle-per-key: 0
|
||||
min-idle-per-key: 10
|
||||
max-idle-per-key: 40
|
||||
max-total-per-key: 40
|
||||
max-total: -1
|
||||
lifo: true
|
||||
fairness: false
|
||||
max-wait-millis: -1
|
||||
min-evictable-idle-time-millis: 1800000
|
||||
lifo: false
|
||||
fairness: true
|
||||
max-wait-millis: 60000
|
||||
min-evictable-idle-time-millis: -1
|
||||
evictor-shutdown-timeout-millis: 10000
|
||||
soft-min-evictable-idle-time-millis: -1
|
||||
soft-min-evictable-idle-time-millis: 300000
|
||||
num-tests-per-eviction-run: 3
|
||||
time-between-eviction-runs-millis: -1
|
||||
time-between-eviction-runs-millis: 30000
|
||||
block-when-exhausted: true
|
||||
remove-abandoned-on-borrow: false
|
||||
remove-abandoned-on-maintenance: true
|
||||
remove-abandoned-timeout-millis: 600000
|
||||
remove-abandoned-logging: true
|
||||
jmx-enabled: true
|
||||
test-on-borrow: false
|
||||
test-on-return: false
|
||||
websocket:
|
||||
ip: 127.0.0.1
|
||||
base-port: 5244
|
||||
base-port: 9244
|
||||
timeout: 60
|
||||
subscription-lag: 120
|
||||
scanner-batch-size: 10000
|
||||
@@ -145,15 +160,19 @@ timely:
|
||||
max-idle-per-key: 40
|
||||
max-total-per-key: 40
|
||||
max-total: -1
|
||||
lifo: true
|
||||
fairness: false
|
||||
max-wait-millis: -1
|
||||
min-evictable-idle-time-millis: 1800000
|
||||
lifo: false
|
||||
fairness: true
|
||||
max-wait-millis: 60000
|
||||
min-evictable-idle-time-millis: -1
|
||||
evictor-shutdown-timeout-millis: 10000
|
||||
soft-min-evictable-idle-time-millis: -1
|
||||
soft-min-evictable-idle-time-millis: 300000
|
||||
num-tests-per-eviction-run: 3
|
||||
time-between-eviction-runs-millis: -1
|
||||
time-between-eviction-runs-millis: 30000
|
||||
block-when-exhausted: true
|
||||
remove-abandoned-on-borrow: false
|
||||
remove-abandoned-on-maintenance: true
|
||||
remove-abandoned-timeout-millis: 600000
|
||||
remove-abandoned-logging: true
|
||||
jmx-enabled: true
|
||||
test-on-borrow: false
|
||||
test-on-return: false
|
||||
+2
-2
@@ -4,13 +4,13 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>2.1.4-SNAPSHOT</version>
|
||||
<version>2.2.3</version>
|
||||
</parent>
|
||||
<artifactId>timely-client</artifactId>
|
||||
<properties>
|
||||
<!-- PEP 440 compliant version gets substituted into src/main/python/template/setup.py -->
|
||||
<!-- use .dev0 instead of -SNAPSHOT -->
|
||||
<python.client.version>2.1.4.dev0</python.client.version>
|
||||
<python.client.version>2.2.3</python.client.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -18,18 +18,27 @@ public class TcpClient implements AutoCloseable {
|
||||
private Socket sock = null;
|
||||
private BufferedWriter out = null;
|
||||
private long connectTime = 0L;
|
||||
private long backoff = 2000;
|
||||
private int bufferSize = -1;
|
||||
private long INIT_BACKOFF = 1000;
|
||||
private long MAX_BACKOFF = 60000;
|
||||
private long backoff = INIT_BACKOFF;
|
||||
private int bufferSize;
|
||||
private long latency;
|
||||
private int writesSinceFlush = 0;
|
||||
private long lastFlushTime = System.currentTimeMillis();
|
||||
|
||||
public TcpClient(String hostname, int port) {
|
||||
this(hostname, port, -1);
|
||||
}
|
||||
|
||||
public TcpClient(String hostname, int port, int bufferSize) {
|
||||
this(hostname, port, bufferSize, -1);
|
||||
}
|
||||
|
||||
public TcpClient(String hostname, int port, int bufferSize, long latency) {
|
||||
this.host = hostname;
|
||||
this.port = port;
|
||||
this.bufferSize = bufferSize;
|
||||
this.latency = latency;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,20 +63,54 @@ public class TcpClient implements AutoCloseable {
|
||||
if (connect() != 0) {
|
||||
throw new IOException();
|
||||
}
|
||||
out.write(metric);
|
||||
writesSinceFlush++;
|
||||
if (bufferSize > 0 && writesSinceFlush >= bufferSize) {
|
||||
flush();
|
||||
try {
|
||||
out.write(metric);
|
||||
writesSinceFlush++;
|
||||
if (bufferSize > 0 && writesSinceFlush >= bufferSize) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace(String.format("Flushing buffer writesSinceFlush >= %d", writesSinceFlush));
|
||||
}
|
||||
flush();
|
||||
}
|
||||
if (latency > 0 && (System.currentTimeMillis() - lastFlushTime) >= latency) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace(String.format("Flushing buffer timeSinceFlush >= %d", latency));
|
||||
}
|
||||
flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
reset();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void flush() throws IOException {
|
||||
if (null != out) {
|
||||
out.flush();
|
||||
writesSinceFlush = 0;
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
out.flush();
|
||||
lastFlushTime = System.currentTimeMillis();
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace(String.format("Flushed %d metrics to socket in %d ms", writesSinceFlush, (lastFlushTime - start)));
|
||||
}
|
||||
writesSinceFlush = 0;
|
||||
} catch (IOException e) {
|
||||
log.error(String.format("Failed to flush %d metrics to socket", writesSinceFlush), e);
|
||||
reset();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void reset() {
|
||||
out = null;
|
||||
sock = null;
|
||||
backoff = INIT_BACKOFF;
|
||||
writesSinceFlush = 0;
|
||||
lastFlushTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the tcp connection to Timely
|
||||
*
|
||||
@@ -75,8 +118,8 @@ public class TcpClient implements AutoCloseable {
|
||||
* if an error occurs
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
log.trace("Shutting down connection to Timely at {}:{}", host, port);
|
||||
public synchronized void close() throws IOException {
|
||||
log.info(String.format("Shutting down connection to Timely at %s:%d", host, port));
|
||||
if (null != sock) {
|
||||
try {
|
||||
if (null != out) {
|
||||
@@ -87,7 +130,7 @@ public class TcpClient implements AutoCloseable {
|
||||
}
|
||||
sock.close();
|
||||
} catch (IOException e) {
|
||||
log.error("Error closing connection to Timely at " + host + ":" + port + ". Error: " + e.getMessage());
|
||||
log.error(String.format("Error closing connection to Timely at %s:%d", host, port), e);
|
||||
} finally {
|
||||
sock = null;
|
||||
}
|
||||
@@ -103,10 +146,10 @@ public class TcpClient implements AutoCloseable {
|
||||
sock = new Socket(host, port);
|
||||
osw = new OutputStreamWriter(sock.getOutputStream(), StandardCharsets.UTF_8);
|
||||
out = new BufferedWriter(osw);
|
||||
backoff = 2000;
|
||||
log.trace("Connected to Timely at {}:{}", host, port);
|
||||
backoff = INIT_BACKOFF;
|
||||
log.info(String.format("Connected to Timely at %s:%d", host, port));
|
||||
} catch (Exception e) {
|
||||
log.error("Error connecting to Timely at {}:{} - {}", host, port, e.getMessage());
|
||||
log.error(String.format("Error connecting to Timely at %s:%d", host, port), e);
|
||||
if (sock != null) {
|
||||
try {
|
||||
sock.close();
|
||||
@@ -132,12 +175,13 @@ public class TcpClient implements AutoCloseable {
|
||||
out = null;
|
||||
}
|
||||
}
|
||||
backoff = backoff * 2;
|
||||
log.info("Will retry connection in {} ms.", backoff);
|
||||
backoff = Math.min(MAX_BACKOFF, backoff * 2);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace(String.format("Will retry connection in %d ms", backoff));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
log.warn("Not writing to Timely, waiting to reconnect");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -147,4 +191,22 @@ public class TcpClient implements AutoCloseable {
|
||||
public long getConnectTime() {
|
||||
return connectTime;
|
||||
}
|
||||
|
||||
public int getWritesSinceFlush() {
|
||||
return writesSinceFlush;
|
||||
}
|
||||
|
||||
public long getTimeSinceFlush() {
|
||||
return System.currentTimeMillis() - lastFlushTime;
|
||||
}
|
||||
|
||||
public synchronized boolean isConnected() {
|
||||
boolean isConnected = (null != sock && sock.isConnected());
|
||||
if (isConnected) {
|
||||
return true;
|
||||
} else {
|
||||
int status = connect();
|
||||
return status == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>2.1.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>collectd-nsq-plugin</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>collectd</groupId>
|
||||
<artifactId>collectd-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>collectd-plugin-parent</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<includes />
|
||||
</artifactSet>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>**/module-info.class</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>shade</id>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>2.1.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>collectd-plugin-parent</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>collectd</groupId>
|
||||
<artifactId>collectd-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.jcip</groupId>
|
||||
<artifactId>jcip-annotations</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-easymock-release-full</artifactId>
|
||||
<classifier>full</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
-321
@@ -1,321 +0,0 @@
|
||||
package timely.collectd.plugin;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.collectd.api.Collectd;
|
||||
import org.collectd.api.OConfigItem;
|
||||
import org.collectd.api.ValueList;
|
||||
|
||||
public abstract class CollectDPluginParent {
|
||||
|
||||
private static final String PUT = "put {0} {1} {2} {3}";
|
||||
private static final String INSTANCE = "instance";
|
||||
private static final String NAME = "name";
|
||||
private static final String SAMPLE_TYPE = "sampleType";
|
||||
private static final String CODE = "code";
|
||||
private static final String PERIOD = ".";
|
||||
private static final String COUNTER = "COUNTER";
|
||||
private static final String GAUGE = "GAUGE";
|
||||
private static final String DERIVE = "DERIVE";
|
||||
private static final String ABSOLUTE = "ABSOLUTE";
|
||||
private static final Pattern STATSD_PATTERN_3_GROUPS = Pattern.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
|
||||
private static final Pattern STATSD_PATTERN_4_GROUPS = Pattern.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
|
||||
private static final Pattern STATSD_PATTERN_6_GROUPS = Pattern.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_#]+)\\.([\\w-_]+)");
|
||||
private static final Pattern ETHSTAT_PATTERN = Pattern.compile("([\\w-_]+)_queue_([\\w-_]+)_([\\w-_]+)");
|
||||
private static final String STATSD_PREFIX = "statsd";
|
||||
private static final String NSQ_PREFIX = STATSD_PREFIX + ".nsq.";
|
||||
private static final Pattern HAPROXY_PATTERN = Pattern.compile("\\[([\\w-_=]+),([\\w-_=]+)\\]");
|
||||
|
||||
private final SMARTCodeMapping smart = new SMARTCodeMapping();
|
||||
protected Map<String,String> addlTags = new TreeMap<>();
|
||||
private boolean debug = false;
|
||||
|
||||
public int config(OConfigItem config) {
|
||||
for (OConfigItem child : config.getChildren()) {
|
||||
switch (child.getKey()) {
|
||||
case "Tags":
|
||||
case "tags":
|
||||
String tagValue = child.getValues().get(0).getString();
|
||||
Arrays.stream(tagValue.split(",")).map(String::trim).forEach(p -> {
|
||||
String[] pair = p.split("=");
|
||||
if (pair.length == 2) {
|
||||
addTag(addlTags, pair[0], pair[1]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "Debug":
|
||||
case "debug":
|
||||
debug = child.getValues().get(0).getBoolean();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public abstract void write(String metric, OutputStream out);
|
||||
|
||||
protected void addTag(Map<String,String> m, String k, String v) {
|
||||
if (k != null && !k.isBlank() && v != null && !v.isBlank()) {
|
||||
m.put(k.trim(), v.trim());
|
||||
}
|
||||
}
|
||||
|
||||
protected void addTag(Map<String,String> m, String kv) {
|
||||
if (kv != null && !kv.isBlank()) {
|
||||
String[] parts = kv.split("=");
|
||||
if (parts.length == 2 && !parts[0].isBlank() && !parts[1].isBlank()) {
|
||||
m.put(parts[0].trim(), parts[1].trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void process(ValueList vl, OutputStream out) {
|
||||
try {
|
||||
processInternal(vl, out);
|
||||
} catch (Exception e) {
|
||||
Collectd.logError(e.getMessage());
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
private void processInternal(ValueList vl, OutputStream out) {
|
||||
debugValueList(vl);
|
||||
|
||||
StringBuilder metric = new StringBuilder();
|
||||
Long timestamp = vl.getTime();
|
||||
Map<String,String> tagMap = new TreeMap<>();
|
||||
String host = vl.getHost();
|
||||
int idx = host.indexOf(PERIOD);
|
||||
if (-1 != idx) {
|
||||
addTag(tagMap, "host", host.substring(0, idx));
|
||||
} else {
|
||||
addTag(tagMap, "host", host);
|
||||
}
|
||||
int nIdx = host.indexOf('n');
|
||||
if (-1 != nIdx) {
|
||||
addTag(tagMap, "rack", host.substring(0, nIdx));
|
||||
}
|
||||
tagMap.putAll(addlTags);
|
||||
|
||||
String plugin = vl.getPlugin();
|
||||
String pluginInstance = vl.getPluginInstance();
|
||||
String type = vl.getType();
|
||||
String typeInstance = vl.getTypeInstance();
|
||||
|
||||
switch (plugin) {
|
||||
case STATSD_PREFIX:
|
||||
Matcher statsd_3_groups = STATSD_PATTERN_3_GROUPS.matcher(typeInstance);
|
||||
Matcher statsd_4_groups = STATSD_PATTERN_4_GROUPS.matcher(typeInstance);
|
||||
Matcher statsd_6_groups = STATSD_PATTERN_6_GROUPS.matcher(typeInstance);
|
||||
String instance = null;
|
||||
if (!typeInstance.startsWith("nsq")) {
|
||||
String[] parts = typeInstance.split("\\.");
|
||||
if (parts.length % 2 == 1 && parts.length >= 3) {
|
||||
switch(parts[0]) {
|
||||
case "dwingest":
|
||||
if (parts.length >= 4) {
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(parts[1]).append(PERIOD).append(parts[3]);
|
||||
instance = parts[0];
|
||||
}
|
||||
break;
|
||||
case "dwquery":
|
||||
if (parts.length >= 4) {
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(parts[1]).append(PERIOD).append(parts[3]);
|
||||
addTag(tagMap, "queryId", parts[0]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// EtsyStatsD format -- metric.(tagName.tagValue)*
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(parts[0]);
|
||||
for (int x = 1; x < parts.length; x += 2) {
|
||||
addTag(tagMap, parts[x], parts[x + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (statsd_4_groups.matches()) {
|
||||
// Here we are processing the statsd metrics coming from the Hadoop Metrics2 StatsDSink without the host name.
|
||||
// The format of metric is: serviceName.contextName.recordName.metricName. The recordName is typically duplicative
|
||||
// and is dropped here. The serviceName is used as the instance.
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(statsd_4_groups.group(2)).append(PERIOD).append(statsd_4_groups.group(4));
|
||||
instance = statsd_4_groups.group(1);
|
||||
}
|
||||
} else if (statsd_3_groups.matches()) {
|
||||
metric.append(NSQ_PREFIX).append(statsd_3_groups.group(2)).append(PERIOD).append(statsd_3_groups.group(3));
|
||||
} else if (statsd_4_groups.matches()) {
|
||||
metric.append(NSQ_PREFIX).append(statsd_4_groups.group(2)).append(PERIOD).append(statsd_4_groups.group(4));
|
||||
instance = statsd_4_groups.group(3);
|
||||
} else if (statsd_6_groups.matches()) {
|
||||
metric.append(NSQ_PREFIX).append(statsd_6_groups.group(4)).append(PERIOD).append(statsd_6_groups.group(6));
|
||||
instance = statsd_6_groups.group(5);
|
||||
} else {
|
||||
// Handle StatsD metrics of unknown formats. If there is a
|
||||
// period in the metric name, use everything up to that as
|
||||
// the instance.
|
||||
int period = typeInstance.indexOf('.');
|
||||
if (-1 == period) {
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(typeInstance);
|
||||
} else {
|
||||
instance = typeInstance.substring(0, period);
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(typeInstance.substring(period + 1));
|
||||
}
|
||||
}
|
||||
if (null != instance) {
|
||||
addTag(tagMap, INSTANCE, instance);
|
||||
}
|
||||
break;
|
||||
case "ethstat":
|
||||
metric.append("sys.ethstat.");
|
||||
if (typeInstance.contains("queue")) {
|
||||
Matcher ethstat_m = ETHSTAT_PATTERN.matcher(typeInstance);
|
||||
if (ethstat_m.matches()) {
|
||||
metric.append(ethstat_m.group(1)).append("_").append(ethstat_m.group(3));
|
||||
addTag(tagMap, "queue", ethstat_m.group(2));
|
||||
} else {
|
||||
metric.append(typeInstance);
|
||||
}
|
||||
} else {
|
||||
metric.append(typeInstance);
|
||||
}
|
||||
addTag(tagMap, INSTANCE, pluginInstance);
|
||||
break;
|
||||
case "hddtemp":
|
||||
metric.append("sys.hddtemp.").append(type);
|
||||
addTag(tagMap, INSTANCE, typeInstance);
|
||||
break;
|
||||
case "smart":
|
||||
int code = -1;
|
||||
String name = null;
|
||||
if (typeInstance.startsWith("attribute-")) {
|
||||
int hyphen = typeInstance.indexOf('-');
|
||||
code = Integer.parseInt(typeInstance.substring(hyphen + 1));
|
||||
name = smart.get(code);
|
||||
}
|
||||
if (code == -1) {
|
||||
if (notEmpty(typeInstance)) {
|
||||
metric.append("sys.smart.").append(typeInstance);
|
||||
} else {
|
||||
metric.append("sys.smart.").append(type);
|
||||
}
|
||||
} else {
|
||||
metric.append("sys.smart.").append(name);
|
||||
addTag(tagMap, CODE, Integer.toString(code));
|
||||
}
|
||||
addTag(tagMap, INSTANCE, pluginInstance);
|
||||
break;
|
||||
case "sensors":
|
||||
if (typeInstance.startsWith("temp")) {
|
||||
addTag(tagMap, INSTANCE, typeInstance.substring(4));
|
||||
}
|
||||
metric.append("sys.sensors.").append(type).append(PERIOD).append(pluginInstance);
|
||||
break;
|
||||
case "haproxy":
|
||||
metric.append("sys.haproxy.").append(typeInstance);
|
||||
Matcher hadoop_m2 = HAPROXY_PATTERN.matcher(pluginInstance);
|
||||
if (hadoop_m2.matches()) {
|
||||
addTag(tagMap, hadoop_m2.group(1));
|
||||
addTag(tagMap, hadoop_m2.group(2));
|
||||
}
|
||||
break;
|
||||
case "ipmi":
|
||||
case "snmp":
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type);
|
||||
addTag(tagMap, INSTANCE, typeInstance.replaceAll(" ", "_"));
|
||||
break;
|
||||
case "GenericJMX":
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type).append(PERIOD).append(typeInstance);
|
||||
String[] pluginInstanceSplit = pluginInstance.split("-");
|
||||
if (pluginInstanceSplit.length > 0) {
|
||||
addTag(tagMap, INSTANCE, pluginInstanceSplit[0].replaceAll(" ", "_"));
|
||||
}
|
||||
if (pluginInstanceSplit.length > 1) {
|
||||
addTag(tagMap, NAME, pluginInstanceSplit[1].replaceAll(" ", "_"));
|
||||
}
|
||||
default:
|
||||
if (notEmpty(type) && notEmpty(typeInstance) && notEmpty(plugin) && notEmpty(pluginInstance)) {
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type).append(PERIOD).append(typeInstance);
|
||||
addTag(tagMap, INSTANCE, pluginInstance.replaceAll(" ", "_"));
|
||||
} else if (notEmpty(type) && notEmpty(typeInstance) && notEmpty(plugin)) {
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type).append(PERIOD).append(typeInstance);
|
||||
} else if (notEmpty(type) && notEmpty(plugin) && notEmpty(pluginInstance)) {
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type);
|
||||
addTag(tagMap, INSTANCE, pluginInstance.replaceAll(" ", "_"));
|
||||
} else if (notEmpty(type) && notEmpty(plugin)) {
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type);
|
||||
} else {
|
||||
Collectd.logWarning("Unhandled metric: " + vl);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
final String metricName = metric.toString().replaceAll(" ", "_");
|
||||
for (int i = 0; i < vl.getValues().size(); i++) {
|
||||
int dataSourceSampleType = vl.getDataSet().getDataSources().get(i).getType();
|
||||
String sampleType = convertType(dataSourceSampleType);
|
||||
if (null != sampleType) {
|
||||
addTag(tagMap, SAMPLE_TYPE, sampleType);
|
||||
}
|
||||
Double value = vl.getValues().get(i).doubleValue();
|
||||
String tagString = tagMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining(" "));
|
||||
String datapoint = MessageFormat.format(PUT, metricName, timestamp.toString(), value.toString(), tagString);
|
||||
logDebug(String.format("Writing: %s", datapoint));
|
||||
write(datapoint + "\n", out);
|
||||
}
|
||||
}
|
||||
|
||||
private void logDebug(String s) {
|
||||
// collectd must be compiled with debug enabled in order for log level debug to work
|
||||
if (debug) {
|
||||
Collectd.logInfo(s);
|
||||
} else {
|
||||
Collectd.logDebug(s);
|
||||
}
|
||||
}
|
||||
|
||||
private void debugValueList(ValueList vl) {
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(String.format("Plugin:%s", vl.getPlugin()));
|
||||
if (vl.getPluginInstance() != null && !vl.getPluginInstance().isBlank()) {
|
||||
sb.append(String.format(" PluginInstance:%s", vl.getPluginInstance()));
|
||||
}
|
||||
sb.append(String.format(" Type:%s", vl.getType()));
|
||||
sb.append(String.format(" TypeInstance:%s", vl.getTypeInstance()));
|
||||
for (int i = 0; i < vl.getValues().size(); i++) {
|
||||
Number value = vl.getValues().get(i);
|
||||
sb.append(String.format(" Value:%s", value.toString()));
|
||||
}
|
||||
logDebug(sb.toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logDebug(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String convertType(int type) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
return COUNTER;
|
||||
case 1:
|
||||
return GAUGE;
|
||||
case 2:
|
||||
return DERIVE;
|
||||
case 3:
|
||||
return ABSOLUTE;
|
||||
default:
|
||||
return GAUGE;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean notEmpty(String arg) {
|
||||
return (null != arg) && !(arg.equals(""));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FindBugsFilter>
|
||||
<Match>
|
||||
<Bug pattern="DM_DEFAULT_ENCODING"/>
|
||||
<Method name="connect" />
|
||||
<Class name="timely.collectd.plugin.WriteTimelyPlugin"/>
|
||||
</Match>
|
||||
</FindBugsFilter>
|
||||
@@ -1,24 +0,0 @@
|
||||
Configuration:
|
||||
status: warn
|
||||
monitorInterval: 60
|
||||
|
||||
Properties:
|
||||
Property:
|
||||
- name: PID
|
||||
value: "????"
|
||||
- name: LOG_PATTERN
|
||||
value: "%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{%5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%wEx"
|
||||
|
||||
Appenders:
|
||||
Console:
|
||||
name: Console
|
||||
target: SYSTEM_OUT
|
||||
follow: true
|
||||
PatternLayout:
|
||||
pattern: "${LOG_PATTERN}"
|
||||
|
||||
Loggers:
|
||||
Root:
|
||||
level: warn
|
||||
AppenderRef:
|
||||
- ref: Console
|
||||
@@ -4,37 +4,43 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>2.1.4-SNAPSHOT</version>
|
||||
<version>2.2.3</version>
|
||||
</parent>
|
||||
<artifactId>collectd-timely-plugin</artifactId>
|
||||
<artifactId>timely-collectd</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>collectd</groupId>
|
||||
<artifactId>collectd-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>collectd-plugin-parent</artifactId>
|
||||
<artifactId>timely-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.jcip</groupId>
|
||||
<artifactId>jcip-annotations</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-easymock-release-full</artifactId>
|
||||
@@ -49,7 +55,17 @@
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<includes />
|
||||
<includes>
|
||||
<include>com.google.guava:guava</include>
|
||||
<include>commons-codec:commons-codec</include>
|
||||
<include>org.apache.commons:commons-lang3</include>
|
||||
<include>org.apache.commons:commons-pool2</include>
|
||||
<include>org.apache.httpcomponents:httpclient</include>
|
||||
<include>org.apache.httpcomponents:httpcore</include>
|
||||
<include>org.slf4j:jcl-over-slf4j</include>
|
||||
<include>org.slf4j:slf4j-api</include>
|
||||
<include>timely:timely-common</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<filters>
|
||||
<filter>
|
||||
@@ -0,0 +1,395 @@
|
||||
package timely.collectd.plugin;
|
||||
|
||||
import static org.slf4j.event.Level.DEBUG;
|
||||
import static org.slf4j.event.Level.WARN;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import timely.util.Exclusions;
|
||||
|
||||
public abstract class CollectDPluginParent implements WritesMetrics, PluginLogger {
|
||||
|
||||
private static final String PUT = "put {0} {1} {2} {3}";
|
||||
private static final String INSTANCE = "instance";
|
||||
private static final String NAME = "name";
|
||||
private static final String SAMPLE_TYPE = "sampleType";
|
||||
private static final String CODE = "code";
|
||||
private static final String PERIOD = ".";
|
||||
private static final Collection<String> HADOOP_CONTEXTS = Arrays.asList("NameNode", "DataNode", "JobManager", "NodeManager", "JobHistoryServer",
|
||||
"ResourceManager", "MRAppMaster", "JvmMetrics", "MapTask", "ReduceTask");
|
||||
private static final Pattern STATSD_PATTERN_3_GROUPS = Pattern.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
|
||||
private static final Pattern STATSD_PATTERN_4_GROUPS = Pattern.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
|
||||
private static final Pattern STATSD_PATTERN_6_GROUPS = Pattern.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_#]+)\\.([\\w-_]+)");
|
||||
private static final Pattern ETHSTAT_QUEUE_PATTERN1 = Pattern.compile("([\\w-_]*)queue_([0-9]+)_([\\w-_]+)");
|
||||
private static final Pattern ETHSTAT_QUEUE_PATTERN2 = Pattern.compile("([\\w-_\\.]*)(tx|rx)([-_]?)([0-9]+)([._])([\\w-_]+)");
|
||||
private static final Pattern ETHSTAT_TRAFFIC_CLASS_PATTERN = Pattern.compile("([\\w-_\\.]*)(tc)([-_]?)([0-9]+)([._])([\\w-_]+)");
|
||||
private static final Pattern ETHSTAT_CHANNEL_PATTERN = Pattern.compile("(ch)([0-9]+)([._])([\\w-_]+)");
|
||||
private static final String STATSD_PREFIX = "statsd";
|
||||
private static final String NSQ_PREFIX = STATSD_PREFIX + ".nsq.";
|
||||
private static final Pattern HAPROXY_PATTERN = Pattern.compile("\\[([\\w-_=]+),([\\w-_=]+)\\]");
|
||||
|
||||
private final SMARTCodeMapping smart = new SMARTCodeMapping();
|
||||
protected Map<String,String> additionalTags = new TreeMap<>();
|
||||
private boolean debug = false;
|
||||
private Exclusions exclusions = new Exclusions();
|
||||
|
||||
public int config(Map<String,Object> configMap) {
|
||||
for (Map.Entry<String,Object> entry : configMap.entrySet()) {
|
||||
switch (entry.getKey().toLowerCase()) {
|
||||
case "tags":
|
||||
String tagValue = (String) entry.getValue();
|
||||
Arrays.stream(tagValue.split(",")).map(String::trim).forEach(p -> {
|
||||
String[] pair = p.split("=");
|
||||
if (pair.length == 2) {
|
||||
addTag(additionalTags, pair[0], pair[1]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "filteredmetricsfile":
|
||||
setFilteredMetricsFile((String) entry.getValue());
|
||||
break;
|
||||
case "filteredtagsfile":
|
||||
setFilteredTagsFile((String) entry.getValue());
|
||||
break;
|
||||
case "debug":
|
||||
debug = (Boolean) entry.getValue();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setAdditionalTags(Map<String,String> additionalTags) {
|
||||
this.additionalTags = additionalTags;
|
||||
}
|
||||
|
||||
public void setFilteredMetricsFile(String filteredMetricsFile) {
|
||||
if (StringUtils.isNotBlank(filteredMetricsFile)) {
|
||||
exclusions.setFilteredMetricsFile(filteredMetricsFile);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFilteredTagsFile(String filteredTagsFile) {
|
||||
if (StringUtils.isNotBlank(filteredTagsFile)) {
|
||||
exclusions.setFilteredTagsFile(filteredTagsFile);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void write(String metric, OutputStream out);
|
||||
|
||||
protected void addTag(Map<String,String> m, String k, String v) {
|
||||
if (k != null && !k.isBlank() && v != null && !v.isBlank()) {
|
||||
k = k.replaceAll("=", ":");
|
||||
v = v.replaceAll("=", ":");
|
||||
m.put(k.trim(), v.trim());
|
||||
}
|
||||
}
|
||||
|
||||
protected void addTag(Map<String,String> m, String kv) {
|
||||
if (kv != null && !kv.isBlank()) {
|
||||
String[] parts = kv.split("=");
|
||||
if (parts.length == 2) {
|
||||
addTag(m, parts[0], parts[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void process(MetricData metricData, OutputStream out) {
|
||||
debugMetricData(metricData);
|
||||
StringBuilder metric = new StringBuilder();
|
||||
Map<String,String> tagMap = new TreeMap<>();
|
||||
|
||||
String host = metricData.getHost();
|
||||
int idx = host.indexOf(PERIOD);
|
||||
if (-1 != idx) {
|
||||
addTag(tagMap, "host", host.substring(0, idx));
|
||||
} else {
|
||||
addTag(tagMap, "host", host);
|
||||
}
|
||||
String[] hostSplit = host.split("\\.");
|
||||
int nIdx = hostSplit[0].lastIndexOf('n');
|
||||
if (-1 != nIdx) {
|
||||
addTag(tagMap, "rack", hostSplit[0].substring(0, nIdx));
|
||||
}
|
||||
tagMap.putAll(additionalTags);
|
||||
|
||||
String plugin = metricData.getPlugin();
|
||||
String pluginInstance = metricData.getPluginInstance();
|
||||
String type = metricData.getType();
|
||||
String typeInstance = metricData.getTypeInstance();
|
||||
List<Pair<Double,String>> values = metricData.getValuePairs();
|
||||
|
||||
switch (plugin) {
|
||||
case STATSD_PREFIX:
|
||||
Matcher statsd_3_groups = STATSD_PATTERN_3_GROUPS.matcher(typeInstance);
|
||||
Matcher statsd_4_groups = STATSD_PATTERN_4_GROUPS.matcher(typeInstance);
|
||||
Matcher statsd_6_groups = STATSD_PATTERN_6_GROUPS.matcher(typeInstance);
|
||||
String instance = null;
|
||||
boolean defaultCase = false;
|
||||
if (!typeInstance.startsWith("nsq")) {
|
||||
String[] parts = typeInstance.split("\\.");
|
||||
if (parts.length >= 4 && HADOOP_CONTEXTS.contains(parts[0])) {
|
||||
// Here we are processing the statsd metrics coming from the Hadoop Metrics2 StatsDSink without the host name.
|
||||
// The format of metric is: serviceName.contextName.recordName.metricName
|
||||
// The serviceName is used as the instance.
|
||||
instance = parts[0];
|
||||
String contextName = parts[1];
|
||||
int firstPeriod = typeInstance.indexOf(".");
|
||||
int lastPeriod = typeInstance.lastIndexOf(".");
|
||||
String metricName = typeInstance.substring(lastPeriod + 1);
|
||||
String recordName = typeInstance.substring(firstPeriod + 1, lastPeriod);
|
||||
// the recordName may contain useful tags such as op=<operation> and user<user>
|
||||
// in addition to a possibly duplicative recordName
|
||||
String[] recordNameSplits = recordName.split("\\.");
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(contextName).append(PERIOD);
|
||||
for (String split : recordNameSplits) {
|
||||
// avoid duplication with either the contextName or instance
|
||||
if (!split.equalsIgnoreCase(contextName) && !split.equalsIgnoreCase(instance)) {
|
||||
if (split.startsWith("NNTopUserOpCounts") && split.contains("windowMs=")) {
|
||||
metric.append("NNTopUserOpCounts").append(PERIOD);
|
||||
addTag(tagMap, split.substring(split.indexOf("windowMs=")));
|
||||
} else if (split.contains("=")) {
|
||||
addTag(tagMap, split);
|
||||
} else {
|
||||
addTag(tagMap, "record", split);
|
||||
}
|
||||
}
|
||||
}
|
||||
metric.append(metricName);
|
||||
} else if (parts.length >= 2 && parts[1].equals("dwquery")) {
|
||||
// These come from Datawave's QueryIterator metrics - the first split part is the queryId
|
||||
// Use statsd plus the rest of the typeInstance after the first period as the metric name
|
||||
int x = typeInstance.indexOf(".");
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(typeInstance.substring(x + 1));
|
||||
addTag(tagMap, "queryId", parts[0]);
|
||||
} else if (statsd_4_groups.matches()) {
|
||||
// Here we are processing the statsd metrics coming from the Hadoop Metrics2 StatsDSink without the host name.
|
||||
// The format of metric is: serviceName.contextName.recordName.metricName. The recordName is typically duplicative
|
||||
// and is dropped here. The serviceName is used as the instance.
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(statsd_4_groups.group(2)).append(PERIOD).append(statsd_4_groups.group(4));
|
||||
instance = statsd_4_groups.group(1);
|
||||
} else if (parts.length >= 1) {
|
||||
// EtsyStatsD format -- metric.(tagName.tagValue)*
|
||||
// Will handle all key.value pairs and truncate at the end if line was malformed or truncated
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(parts[0]);
|
||||
for (int x = 1; x + 1 < parts.length; x += 2) {
|
||||
addTag(tagMap, parts[x], parts[x + 1]);
|
||||
}
|
||||
if (parts.length % 2 == 0) {
|
||||
log(DEBUG, String.format("Using available tags from malformed/truncated line %s", typeInstance));
|
||||
}
|
||||
} else {
|
||||
defaultCase = true;
|
||||
}
|
||||
} else {
|
||||
if (statsd_3_groups.matches()) {
|
||||
metric.append(NSQ_PREFIX).append(statsd_3_groups.group(2)).append(PERIOD).append(statsd_3_groups.group(3));
|
||||
} else if (statsd_4_groups.matches()) {
|
||||
metric.append(NSQ_PREFIX).append(statsd_4_groups.group(2)).append(PERIOD).append(statsd_4_groups.group(4));
|
||||
instance = statsd_4_groups.group(3);
|
||||
} else if (statsd_6_groups.matches()) {
|
||||
metric.append(NSQ_PREFIX).append(statsd_6_groups.group(4)).append(PERIOD).append(statsd_6_groups.group(6));
|
||||
instance = statsd_6_groups.group(5);
|
||||
} else {
|
||||
defaultCase = true;
|
||||
}
|
||||
}
|
||||
if (defaultCase) {
|
||||
// Handle StatsD metrics of unknown formats. If there is a
|
||||
// period in the metric name, use everything up to that as
|
||||
// the instance.
|
||||
int period = typeInstance.indexOf('.');
|
||||
if (-1 == period) {
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(typeInstance);
|
||||
} else {
|
||||
instance = typeInstance.substring(0, period);
|
||||
metric.append(STATSD_PREFIX).append(PERIOD).append(typeInstance.substring(period + 1));
|
||||
}
|
||||
}
|
||||
if (null != instance) {
|
||||
addTag(tagMap, INSTANCE, instance);
|
||||
}
|
||||
break;
|
||||
case "ethstat":
|
||||
metric.append("sys.ethstat.");
|
||||
if (typeInstance.matches(ETHSTAT_QUEUE_PATTERN1.pattern())) {
|
||||
Matcher ethstat_m = ETHSTAT_QUEUE_PATTERN1.matcher(typeInstance);
|
||||
if (ethstat_m.matches()) {
|
||||
metric.append(ethstat_m.group(1));
|
||||
metric.append("queue_");
|
||||
metric.append(ethstat_m.group(3));
|
||||
addTag(tagMap, "queue", ethstat_m.group(2));
|
||||
}
|
||||
} else if (typeInstance.matches(ETHSTAT_QUEUE_PATTERN2.pattern())) {
|
||||
Matcher ethstat_m = ETHSTAT_QUEUE_PATTERN2.matcher(typeInstance);
|
||||
if (ethstat_m.matches()) {
|
||||
metric.append(ethstat_m.group(1));
|
||||
metric.append(ethstat_m.group(2));
|
||||
metric.append("_queue_");
|
||||
metric.append(ethstat_m.group(6));
|
||||
addTag(tagMap, "queue", ethstat_m.group(4));
|
||||
}
|
||||
} else if (typeInstance.matches(ETHSTAT_TRAFFIC_CLASS_PATTERN.pattern())) {
|
||||
Matcher ethstat_m = ETHSTAT_TRAFFIC_CLASS_PATTERN.matcher(typeInstance);
|
||||
if (ethstat_m.matches()) {
|
||||
metric.append(ethstat_m.group(1));
|
||||
metric.append(ethstat_m.group(2));
|
||||
metric.append(ethstat_m.group(5));
|
||||
metric.append(ethstat_m.group(6));
|
||||
addTag(tagMap, "trafficClass", ethstat_m.group(4));
|
||||
}
|
||||
} else if (typeInstance.matches(ETHSTAT_CHANNEL_PATTERN.pattern())) {
|
||||
Matcher ethstat_m = ETHSTAT_CHANNEL_PATTERN.matcher(typeInstance);
|
||||
if (ethstat_m.matches()) {
|
||||
metric.append(ethstat_m.group(1));
|
||||
metric.append("_");
|
||||
metric.append(ethstat_m.group(4));
|
||||
addTag(tagMap, "channel", ethstat_m.group(2));
|
||||
}
|
||||
} else {
|
||||
metric.append(typeInstance);
|
||||
}
|
||||
addTag(tagMap, INSTANCE, pluginInstance);
|
||||
break;
|
||||
case "hddtemp":
|
||||
metric.append("sys.hddtemp.").append(type);
|
||||
addTag(tagMap, INSTANCE, typeInstance);
|
||||
break;
|
||||
case "smart":
|
||||
int code = -1;
|
||||
String name = null;
|
||||
if (typeInstance.startsWith("attribute-")) {
|
||||
int hyphen = typeInstance.indexOf('-');
|
||||
code = Integer.parseInt(typeInstance.substring(hyphen + 1));
|
||||
name = smart.get(code);
|
||||
}
|
||||
if (code == -1) {
|
||||
if (notEmpty(typeInstance)) {
|
||||
metric.append("sys.smart.").append(typeInstance);
|
||||
} else {
|
||||
metric.append("sys.smart.").append(type);
|
||||
}
|
||||
} else {
|
||||
metric.append("sys.smart.").append(name);
|
||||
addTag(tagMap, CODE, Integer.toString(code));
|
||||
}
|
||||
addTag(tagMap, INSTANCE, pluginInstance);
|
||||
break;
|
||||
case "sensors":
|
||||
if (typeInstance.startsWith("temp")) {
|
||||
addTag(tagMap, INSTANCE, typeInstance.substring(4));
|
||||
}
|
||||
metric.append("sys.sensors.").append(type).append(PERIOD).append(pluginInstance);
|
||||
break;
|
||||
case "haproxy":
|
||||
metric.append("sys.haproxy.").append(typeInstance);
|
||||
Matcher haproxy_m = HAPROXY_PATTERN.matcher(pluginInstance);
|
||||
if (haproxy_m.matches()) {
|
||||
addTag(tagMap, haproxy_m.group(1));
|
||||
addTag(tagMap, haproxy_m.group(2));
|
||||
}
|
||||
break;
|
||||
case "ipmi":
|
||||
case "snmp":
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type);
|
||||
addTag(tagMap, INSTANCE, typeInstance.replaceAll(" ", "_"));
|
||||
break;
|
||||
case "load":
|
||||
metric.append("sys.load.").append(plugin).append(PERIOD).append(type);
|
||||
// plugin returns 1 min, 5 min, 15 min averages, but Timely can
|
||||
// downsample on its own so we only use the first (1 min) value
|
||||
Pair<Double,String> first = values.get(0);
|
||||
values.clear();
|
||||
values.add(first);
|
||||
break;
|
||||
case "GenericJMX":
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type).append(PERIOD).append(typeInstance);
|
||||
String[] pluginInstanceSplit = pluginInstance.split("-");
|
||||
if (pluginInstanceSplit.length > 0) {
|
||||
addTag(tagMap, INSTANCE, pluginInstanceSplit[0].replaceAll(" ", "_"));
|
||||
}
|
||||
if (pluginInstanceSplit.length > 1) {
|
||||
addTag(tagMap, NAME, pluginInstanceSplit[1].replaceAll(" ", "_"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (notEmpty(type) && notEmpty(typeInstance) && notEmpty(plugin) && notEmpty(pluginInstance)) {
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type).append(PERIOD).append(typeInstance);
|
||||
addTag(tagMap, INSTANCE, pluginInstance.replaceAll(" ", "_"));
|
||||
} else if (notEmpty(type) && notEmpty(typeInstance) && notEmpty(plugin)) {
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type).append(PERIOD).append(typeInstance);
|
||||
} else if (notEmpty(type) && notEmpty(plugin) && notEmpty(pluginInstance)) {
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type);
|
||||
addTag(tagMap, INSTANCE, pluginInstance.replaceAll(" ", "_"));
|
||||
} else if (notEmpty(type) && notEmpty(plugin)) {
|
||||
metric.append("sys.").append(plugin).append(PERIOD).append(type);
|
||||
} else {
|
||||
log(WARN, "Unhandled metric: " + metricData);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
final String metricName = metric.toString().replaceAll(" ", "_");
|
||||
for (Pair<Double,String> pair : values) {
|
||||
addTag(tagMap, SAMPLE_TYPE, pair.getRight());
|
||||
Double value = pair.getLeft();
|
||||
Long timestamp = metricData.getTimestamp();
|
||||
String tagString = tagMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining(" "));
|
||||
|
||||
if (metricName.isBlank() || timestamp == null || value == null) {
|
||||
log(DEBUG, String.format("Not writing unhandled metric: plugin:%s pluginInstance:%s type:%s typeInstance:%s", plugin, pluginInstance, type,
|
||||
typeInstance));
|
||||
} else {
|
||||
String datapoint = MessageFormat.format(PUT, metricName, timestamp.toString(), value.toString(), tagString);
|
||||
if (exclusions.filterMetric(datapoint)) {
|
||||
log(DEBUG, String.format("Not writing excluded metric: %s", datapoint));
|
||||
} else {
|
||||
datapoint = exclusions.filterExcludedTags(datapoint);
|
||||
log(DEBUG, String.format("Writing: %s", datapoint));
|
||||
write(datapoint + "\n", out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void debugMetricData(MetricData metricData) {
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(String.format("Plugin:%s", metricData.getPlugin()));
|
||||
if (metricData.getPluginInstance() != null && !metricData.getPluginInstance().isBlank()) {
|
||||
sb.append(String.format(" PluginInstance:%s", metricData.getPluginInstance()));
|
||||
}
|
||||
sb.append(String.format(" Type:%s", metricData.getType()));
|
||||
sb.append(String.format(" TypeInstance:%s", metricData.getTypeInstance()));
|
||||
for (int i = 0; i < metricData.getValuePairs().size(); i++) {
|
||||
Pair<Double,String> value = metricData.getValuePairs().get(i);
|
||||
sb.append(String.format(" Value:%s", value.getLeft().toString()));
|
||||
}
|
||||
log(DEBUG, sb.toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log(DEBUG, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean notEmpty(String arg) {
|
||||
return (null != arg) && !(arg.equals(""));
|
||||
}
|
||||
|
||||
public boolean isDebug() {
|
||||
return debug;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package timely.collectd.plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.collectd.api.ValueList;
|
||||
|
||||
public class MetricData {
|
||||
|
||||
public static final String COUNTER = "COUNTER";
|
||||
public static final String GAUGE = "GAUGE";
|
||||
public static final String DERIVE = "DERIVE";
|
||||
public static final String ABSOLUTE = "ABSOLUTE";
|
||||
|
||||
private Long timestamp;
|
||||
private String host;
|
||||
private String plugin;
|
||||
private String pluginInstance;
|
||||
private String type;
|
||||
private String typeInstance;
|
||||
private List<Pair<Double,String>> valuePairs = new ArrayList<>();
|
||||
|
||||
public MetricData(Long timestamp, String host, String plugin, String pluginInstance, String type, String typeInstance, List<Double> values,
|
||||
List<String> valueTypes) {
|
||||
this.timestamp = timestamp;
|
||||
this.host = host;
|
||||
this.plugin = plugin;
|
||||
this.pluginInstance = pluginInstance;
|
||||
this.type = type;
|
||||
this.typeInstance = typeInstance;
|
||||
for (int x = 0; x < values.size(); x++) {
|
||||
Double value = values.get(x);
|
||||
String valueType = valueTypes.size() > x ? valueTypes.get(x) : "GAUGE";
|
||||
valuePairs.add(Pair.of(value, valueType));
|
||||
}
|
||||
}
|
||||
|
||||
public MetricData(ValueList vl) {
|
||||
this.timestamp = vl.getTime();
|
||||
this.host = vl.getHost();
|
||||
this.plugin = vl.getPlugin();
|
||||
this.pluginInstance = vl.getPluginInstance();
|
||||
this.type = vl.getType();
|
||||
this.typeInstance = vl.getTypeInstance();
|
||||
List<Number> valueList = vl.getValues();
|
||||
List<String> valueTypes = vl.getDataSet().getDataSources().stream().map(ds -> convertType(ds.getType())).collect(Collectors.toList());
|
||||
for (int x = 0; x < vl.getValues().size(); x++) {
|
||||
Number n = valueList.get(x);
|
||||
String type = valueTypes.size() > x ? valueTypes.get(x) : "GAUGE";
|
||||
valuePairs.add(Pair.of(n.doubleValue(), type));
|
||||
}
|
||||
}
|
||||
|
||||
public Long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(Long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public void setPlugin(String plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public String getPluginInstance() {
|
||||
return pluginInstance;
|
||||
}
|
||||
|
||||
public void setPluginInstance(String pluginInstance) {
|
||||
this.pluginInstance = pluginInstance;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getTypeInstance() {
|
||||
return typeInstance;
|
||||
}
|
||||
|
||||
public void setTypeInstance(String typeInstance) {
|
||||
this.typeInstance = typeInstance;
|
||||
}
|
||||
|
||||
public List<Pair<Double,String>> getValuePairs() {
|
||||
return valuePairs;
|
||||
}
|
||||
|
||||
public void setValuePairs(List<Pair<Double,String>> valuePairs) {
|
||||
this.valuePairs = valuePairs;
|
||||
}
|
||||
|
||||
public static String convertType(int type) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
return COUNTER;
|
||||
case 1:
|
||||
return GAUGE;
|
||||
case 2:
|
||||
return DERIVE;
|
||||
case 3:
|
||||
return ABSOLUTE;
|
||||
default:
|
||||
return GAUGE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("timestamp", timestamp).append("host", host).append("plugin", plugin).append("pluginInstance", pluginInstance)
|
||||
.append("type", type).append("typeInstance", typeInstance).append("valuePairs", valuePairs).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package timely.collectd.plugin;
|
||||
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
public interface PluginLogger {
|
||||
|
||||
void log(Level level, String s);
|
||||
}
|
||||
+9
-8
@@ -1,5 +1,6 @@
|
||||
package timely.collectd.plugin;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
@@ -8,7 +9,6 @@ import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.collectd.api.OConfigItem;
|
||||
|
||||
public class PooledCloseableHttpClientFactory implements PooledObjectFactory<CloseableHttpClient> {
|
||||
|
||||
@@ -17,24 +17,25 @@ public class PooledCloseableHttpClientFactory implements PooledObjectFactory<Clo
|
||||
private int socketTimeout = 60000; // 60 seconds in milliseconds
|
||||
private long connectionTimeToLive = 300000; // 300 seconds in milliseconds
|
||||
|
||||
public int config(OConfigItem config) {
|
||||
for (OConfigItem child : config.getChildren()) {
|
||||
switch (child.getKey()) {
|
||||
public int config(Map<String,Object> configMap) {
|
||||
for (Map.Entry<String,Object> entry : configMap.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
switch (entry.getKey()) {
|
||||
case "connectionRequestTimeout":
|
||||
case "ConnectionRequestTimeout":
|
||||
connectionRequestTimeout = Integer.parseInt(child.getValues().get(0).getString());
|
||||
connectionRequestTimeout = Integer.parseInt((String) value);
|
||||
break;
|
||||
case "connectTimeout":
|
||||
case "ConnectTimeout":
|
||||
connectTimeout = Integer.parseInt(child.getValues().get(0).getString());
|
||||
connectTimeout = Integer.parseInt((String) value);
|
||||
break;
|
||||
case "socketTimeout":
|
||||
case "SocketTimeout":
|
||||
socketTimeout = Integer.parseInt(child.getValues().get(0).getString());
|
||||
socketTimeout = Integer.parseInt((String) value);
|
||||
break;
|
||||
case "connectionTimeToLive":
|
||||
case "ConnectionTimeToLive":
|
||||
connectionTimeToLive = Long.parseLong(child.getValues().get(0).getString());
|
||||
connectionTimeToLive = Long.parseLong((String) value);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
+15
-15
@@ -1,12 +1,12 @@
|
||||
package timely.collectd.plugin;
|
||||
|
||||
import java.net.Socket;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.PooledObjectFactory;
|
||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
import org.collectd.api.Collectd;
|
||||
import org.collectd.api.OConfigItem;
|
||||
|
||||
public class PooledSocketFactory implements PooledObjectFactory<Socket> {
|
||||
|
||||
@@ -16,26 +16,27 @@ public class PooledSocketFactory implements PooledObjectFactory<Socket> {
|
||||
private int socketTimeout = 60000; // 60 seconds in milliseconds
|
||||
private long connectionTimeToLive = 300000; // 300 seconds in milliseconds
|
||||
|
||||
public int config(OConfigItem config) {
|
||||
for (OConfigItem child : config.getChildren()) {
|
||||
switch (child.getKey()) {
|
||||
public int config(Map<String,Object> configMap) {
|
||||
for (Map.Entry<String,Object> entry : configMap.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
switch (entry.getKey()) {
|
||||
case "host":
|
||||
case "hostname":
|
||||
case "Host":
|
||||
case "HostName":
|
||||
host = child.getValues().get(0).getString();
|
||||
host = (String) value;
|
||||
break;
|
||||
case "Port":
|
||||
case "port":
|
||||
port = Integer.parseInt(child.getValues().get(0).getString());
|
||||
port = Integer.parseInt((String) value);
|
||||
break;
|
||||
case "socketTimeout":
|
||||
case "SocketTimeout":
|
||||
socketTimeout = Integer.parseInt(child.getValues().get(0).getString());
|
||||
socketTimeout = Integer.parseInt((String) value);
|
||||
break;
|
||||
case "connectionTimeToLive":
|
||||
case "ConnectionTimeToLive":
|
||||
connectionTimeToLive = Long.parseLong(child.getValues().get(0).getString());
|
||||
connectionTimeToLive = Long.parseLong((String) value);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -80,15 +81,15 @@ public class PooledSocketFactory implements PooledObjectFactory<Socket> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PooledObject<Socket> makeObject() throws Exception {
|
||||
public PooledObject<Socket> makeObject() {
|
||||
return new DefaultPooledObject<>(connect());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyObject(PooledObject<Socket> pooledObject) throws Exception {
|
||||
public void destroyObject(PooledObject<Socket> pooledObject) {
|
||||
try {
|
||||
Collectd.logDebug("Shutting down connection to Timely at " + host + ":" + port);
|
||||
Socket socket = (Socket) pooledObject.getObject();
|
||||
Socket socket = pooledObject.getObject();
|
||||
if (socket != null) {
|
||||
socket.close();
|
||||
}
|
||||
@@ -96,7 +97,6 @@ public class PooledSocketFactory implements PooledObjectFactory<Socket> {
|
||||
Collectd.logError("Error closing connection to Timely at " + host + ":" + port + ". Error: " + e.getMessage());
|
||||
} finally {
|
||||
pooledObject.invalidate();
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,17 +107,17 @@ public class PooledSocketFactory implements PooledObjectFactory<Socket> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Socket socket = (Socket) pooledObject.getObject();
|
||||
Socket socket = pooledObject.getObject();
|
||||
return socket != null && !socket.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activateObject(PooledObject<Socket> pooledObject) throws Exception {
|
||||
public void activateObject(PooledObject<Socket> pooledObject) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivateObject(PooledObject<Socket> pooledObject) throws Exception {
|
||||
public void passivateObject(PooledObject<Socket> pooledObject) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+66
-26
@@ -4,6 +4,8 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
@@ -19,7 +21,9 @@ import org.collectd.api.CollectdConfigInterface;
|
||||
import org.collectd.api.CollectdShutdownInterface;
|
||||
import org.collectd.api.CollectdWriteInterface;
|
||||
import org.collectd.api.OConfigItem;
|
||||
import org.collectd.api.OConfigValue;
|
||||
import org.collectd.api.ValueList;
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -46,14 +50,28 @@ public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConf
|
||||
Collectd.registerWrite(WriteNSQPlugin.class.getName(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(MetricData metricData) {
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(baos)) {
|
||||
super.process(metricData, out);
|
||||
out.flush();
|
||||
send(baos);
|
||||
} catch (Exception e) {
|
||||
Collectd.logError("Error sending metrics to NSQ: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(ValueList vl) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(baos);
|
||||
super.process(vl, out);
|
||||
MetricData metricData = new MetricData(vl);
|
||||
write(metricData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int send(ByteArrayOutputStream baos) {
|
||||
|
||||
CloseableHttpClient client = null;
|
||||
try {
|
||||
out.flush();
|
||||
HttpPost post = new HttpPost(endpoint);
|
||||
EntityBuilder request = EntityBuilder.create();
|
||||
request.setBinary(baos.toByteArray());
|
||||
@@ -79,15 +97,13 @@ public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConf
|
||||
} catch (IOException e1) {}
|
||||
try {
|
||||
clientPool.invalidateObject(client);
|
||||
client = null;
|
||||
} catch (Exception e2) {}
|
||||
}
|
||||
} finally {
|
||||
if (client != null) {
|
||||
clientPool.returnObject(client);
|
||||
}
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -113,23 +129,22 @@ public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConf
|
||||
|
||||
@Override
|
||||
public int config(OConfigItem config) {
|
||||
super.config(config);
|
||||
GenericObjectPoolConfig<CloseableHttpClient> poolConfig = new GenericObjectPoolConfig<>();
|
||||
// use max size for maxTotal and maxIdle
|
||||
// no need to activate or passivate
|
||||
poolConfig.setMaxTotal(POOL_MAX_SIZE);
|
||||
poolConfig.setMaxIdle(POOL_MAX_SIZE);
|
||||
poolConfig.setTestOnReturn(true);
|
||||
PooledCloseableHttpClientFactory pooledCloseableHttpClientFactory = new PooledCloseableHttpClientFactory();
|
||||
pooledCloseableHttpClientFactory.config(config);
|
||||
|
||||
for (OConfigItem child : config.getChildren()) {
|
||||
switch (child.getKey()) {
|
||||
Map<String,Object> configMap = new HashMap<>();
|
||||
for (OConfigItem c : config.getChildren()) {
|
||||
String key = c.getKey();
|
||||
OConfigValue value = c.getValues().get(0);
|
||||
int type = value.getType();
|
||||
if (type == 0) {
|
||||
configMap.put(key, value.getString());
|
||||
} else if (type == 1) {
|
||||
configMap.put(key, value.getNumber());
|
||||
} else if (type == 2) {
|
||||
configMap.put(key, value.getBoolean());
|
||||
}
|
||||
switch (key.toLowerCase()) {
|
||||
case "host":
|
||||
case "hostname":
|
||||
case "Host":
|
||||
case "HostName":
|
||||
String hostString = child.getValues().get(0).getString();
|
||||
String hostString = value.getString();
|
||||
String[] hosts = hostString.split(",");
|
||||
if (hosts.length == 1) {
|
||||
host = hosts[0];
|
||||
@@ -137,24 +152,49 @@ public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConf
|
||||
host = hosts[random.nextInt(hosts.length)];
|
||||
}
|
||||
break;
|
||||
case "Port":
|
||||
case "port":
|
||||
port = Integer.parseInt(child.getValues().get(0).getString());
|
||||
port = Integer.parseInt(value.getString());
|
||||
break;
|
||||
case "topic":
|
||||
case "Topic":
|
||||
topic = child.getValues().get(0).getString();
|
||||
topic = value.getString();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
GenericObjectPoolConfig<CloseableHttpClient> poolConfig = new GenericObjectPoolConfig<>();
|
||||
// use max size for maxTotal and maxIdle
|
||||
// no need to activate or passivate
|
||||
poolConfig.setMaxTotal(POOL_MAX_SIZE);
|
||||
poolConfig.setMaxIdle(POOL_MAX_SIZE);
|
||||
poolConfig.setTestOnReturn(true);
|
||||
PooledCloseableHttpClientFactory pooledCloseableHttpClientFactory = new PooledCloseableHttpClientFactory();
|
||||
pooledCloseableHttpClientFactory.config(configMap);
|
||||
|
||||
if (host == null || port == 0 || topic == null) {
|
||||
Collectd.logError("NSQ host, port, and topic must be configured");
|
||||
return -1;
|
||||
}
|
||||
this.clientPool = new GenericObjectPool<>(pooledCloseableHttpClientFactory, poolConfig);
|
||||
this.endpoint = "http://" + host + ":" + port + "/mpub?topic=" + topic;
|
||||
super.config(configMap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void log(Level level, String s) {
|
||||
// collectd must be compiled with debug enabled in order for log level debug to work
|
||||
if (isDebug()) {
|
||||
Collectd.logInfo(s);
|
||||
} else {
|
||||
if (level.equals(Level.DEBUG)) {
|
||||
Collectd.logDebug(s);
|
||||
} else if (level.equals(Level.INFO)) {
|
||||
Collectd.logInfo(s);
|
||||
} else if (level.equals(Level.WARN)) {
|
||||
Collectd.logWarning(s);
|
||||
} else if (level.equals(Level.ERROR)) {
|
||||
Collectd.logError(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
-8
@@ -6,6 +6,8 @@ import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
@@ -14,7 +16,9 @@ import org.collectd.api.CollectdConfigInterface;
|
||||
import org.collectd.api.CollectdShutdownInterface;
|
||||
import org.collectd.api.CollectdWriteInterface;
|
||||
import org.collectd.api.OConfigItem;
|
||||
import org.collectd.api.OConfigValue;
|
||||
import org.collectd.api.ValueList;
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -35,15 +39,15 @@ public class WriteTimelyPlugin extends CollectDPluginParent implements CollectdC
|
||||
Collectd.registerWrite(WriteTimelyPlugin.class.getName(), this);
|
||||
}
|
||||
|
||||
public int write(ValueList vl) {
|
||||
|
||||
@Override
|
||||
public void write(MetricData metricData) {
|
||||
Socket socket = null;
|
||||
try {
|
||||
socket = socketPool.borrowObject();
|
||||
if (socket == null) {
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
super.process(vl, socket.getOutputStream());
|
||||
super.process(metricData, socket.getOutputStream());
|
||||
} catch (Exception e) {
|
||||
Collectd.logWarning(e.getMessage());
|
||||
try {
|
||||
@@ -55,12 +59,16 @@ public class WriteTimelyPlugin extends CollectDPluginParent implements CollectdC
|
||||
} catch (IOException e1) {
|
||||
Collectd.logError(e1.getMessage());
|
||||
}
|
||||
return -1;
|
||||
} finally {
|
||||
if (socket != null) {
|
||||
socketPool.returnObject(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int write(ValueList vl) {
|
||||
MetricData metricData = new MetricData(vl);
|
||||
write(metricData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -80,10 +88,23 @@ public class WriteTimelyPlugin extends CollectDPluginParent implements CollectdC
|
||||
}
|
||||
|
||||
public int config(OConfigItem config) {
|
||||
super.config(config);
|
||||
int retval = 0;
|
||||
Map<String,Object> configMap = new HashMap<>();
|
||||
for (OConfigItem c : config.getChildren()) {
|
||||
String key = c.getKey();
|
||||
OConfigValue value = c.getValues().get(0);
|
||||
int type = value.getType();
|
||||
if (type == 0) {
|
||||
configMap.put(key, value.getString());
|
||||
} else if (type == 1) {
|
||||
configMap.put(key, value.getNumber());
|
||||
} else if (type == 2) {
|
||||
configMap.put(key, value.getBoolean());
|
||||
}
|
||||
}
|
||||
|
||||
int retval;
|
||||
PooledSocketFactory socketFactory = new PooledSocketFactory();
|
||||
retval = socketFactory.config(config);
|
||||
retval = socketFactory.config(configMap);
|
||||
if (retval == 0) {
|
||||
GenericObjectPoolConfig<Socket> poolConfig = new GenericObjectPoolConfig<>();
|
||||
// use max size for maxTotal and maxIdle
|
||||
@@ -93,7 +114,24 @@ public class WriteTimelyPlugin extends CollectDPluginParent implements CollectdC
|
||||
poolConfig.setTestOnReturn(true);
|
||||
socketPool = new GenericObjectPool<>(socketFactory, poolConfig);
|
||||
}
|
||||
super.config(configMap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
public void log(Level level, String s) {
|
||||
// collectd must be compiled with debug enabled in order for log level debug to work
|
||||
if (isDebug()) {
|
||||
Collectd.logInfo(s);
|
||||
} else {
|
||||
if (level.equals(Level.DEBUG)) {
|
||||
Collectd.logDebug(s);
|
||||
} else if (level.equals(Level.INFO)) {
|
||||
Collectd.logInfo(s);
|
||||
} else if (level.equals(Level.WARN)) {
|
||||
Collectd.logWarning(s);
|
||||
} else if (level.equals(Level.ERROR)) {
|
||||
Collectd.logError(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package timely.collectd.plugin;
|
||||
|
||||
public interface WritesMetrics {
|
||||
|
||||
void write(MetricData metricData);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FindBugsFilter>
|
||||
<Match>
|
||||
<Class name="timely.collectd.plugin.MetricData" />
|
||||
<Bug pattern="EI_EXPOSE_REP" />
|
||||
</Match>
|
||||
<Match>
|
||||
<Class name="timely.collectd.plugin.MetricData" />
|
||||
<Bug pattern="EI_EXPOSE_REP2" />
|
||||
</Match>
|
||||
<Match>
|
||||
<Class name="timely.collectd.plugin.CollectDPluginParent" />
|
||||
<Bug pattern="EI_EXPOSE_REP2" />
|
||||
</Match>
|
||||
</FindBugsFilter>
|
||||
+164
-46
@@ -3,6 +3,7 @@ package timely.collectd.plugin;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.collectd.api.Collectd;
|
||||
@@ -13,20 +14,23 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.api.easymock.PowerMock;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
import net.jcip.annotations.NotThreadSafe;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PowerMockIgnore("jdk.internal.reflect.*")
|
||||
@PrepareForTest({Collectd.class})
|
||||
@NotThreadSafe
|
||||
public class PluginParentTest {
|
||||
|
||||
public class TestPlugin extends CollectDPluginParent {
|
||||
private Logger log = LoggerFactory.getLogger(this.getClass().getName());
|
||||
|
||||
public TestPlugin() {
|
||||
super.addlTags.put("addl1", "foo");
|
||||
super.additionalTags.put("addl1", "foo");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -34,6 +38,19 @@ public class PluginParentTest {
|
||||
result = metric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, String s) {
|
||||
log.debug(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(MetricData metricData) {
|
||||
try {
|
||||
process(metricData, null);
|
||||
} catch (Exception e) {
|
||||
log(Level.ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String HOST = "r01n01.test";
|
||||
@@ -41,12 +58,13 @@ public class PluginParentTest {
|
||||
public String result = null;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
public void setup() {
|
||||
result = null;
|
||||
PowerMock.suppress(PowerMock.everythingDeclaredIn(Collectd.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatsDHadoopFormat() throws Exception {
|
||||
public void testStatsDHadoopFormat() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("statsd");
|
||||
@@ -59,12 +77,12 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put statsd.dfs.BlocksRead 1456156976840 1.0 host=r01n01 rack=r01 addl1=foo instance=DataNode sample=value sampleType=GAUGE\n", result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put statsd.dfs.BlocksRead 1456156976840 1.0 addl1=foo host=r01n01 instance=DataNode rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatsDUnknownFormat() throws Exception {
|
||||
public void testStatsDUnknownFormat() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("statsd");
|
||||
@@ -77,12 +95,12 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put statsd.baz 1456156976840 1.0 host=r01n01 rack=r01 addl1=foo sample=value sampleType=GAUGE\n", result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put statsd.baz 1456156976840 1.0 addl1=foo host=r01n01 rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatsDUnknownFormat2() throws Exception {
|
||||
public void testStatsDUnknownFormat2() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("statsd");
|
||||
@@ -95,12 +113,12 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put statsd.baz 1456156976840 1.0 host=r01n01 rack=r01 addl1=foo instance=bar sample=value sampleType=GAUGE\n", result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put statsd.bar 1456156976840 1.0 addl1=foo host=r01n01 rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHddTemp() throws Exception {
|
||||
public void testHddTemp() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("hddtemp");
|
||||
@@ -113,12 +131,12 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put sys.hddtemp.temperature 1456156976840 35.0 host=r01n01 rack=r01 addl1=foo instance=sda sample=value sampleType=GAUGE\n", result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.hddtemp.temperature 1456156976840 35.0 addl1=foo host=r01n01 instance=sda rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmart1() throws Exception {
|
||||
public void testSmart1() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("smart");
|
||||
@@ -131,12 +149,12 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put sys.smart.smart_badsectors 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo instance=sda sample=value sampleType=GAUGE\n", result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.smart.smart_badsectors 1456156976840 0.0 addl1=foo host=r01n01 instance=sda rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmart2() throws Exception {
|
||||
public void testSmart2() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("smart");
|
||||
@@ -150,12 +168,12 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put sys.smart.raw-read-error-rate 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo instance=sda sample=value sampleType=GAUGE\n", result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.smart.raw-read-error-rate 1456156976840 0.0 addl1=foo host=r01n01 instance=sda rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmartCode() throws Exception {
|
||||
public void testSmartCode() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("smart");
|
||||
@@ -169,13 +187,12 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put sys.smart.Total_LBAs_Read 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo code=242 instance=sda sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.smart.Total_LBAs_Read 1456156976840 0.0 addl1=foo code=242 host=r01n01 instance=sda rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnmp() throws Exception {
|
||||
public void testSnmp() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("snmp");
|
||||
@@ -189,8 +206,8 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put sys.snmp.if_octets 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo instance=Ethernet1 sample=value sampleType=GAUGE\n", result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.snmp.if_octets 1456156976840 0.0 addl1=foo host=r01n01 instance=Ethernet1 rack=r01 sampleType=GAUGE\n", result);
|
||||
|
||||
}
|
||||
|
||||
@@ -209,9 +226,8 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put sys.sensors.temperature.coretemp-isa-0000 1456156976840 35.0 host=r01n01 rack=r01 addl1=foo instance=1 sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.sensors.temperature.coretemp-isa-0000 1456156976840 35.0 addl1=foo host=r01n01 instance=1 rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -228,8 +244,8 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put sys.haproxy.run_queue 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo sample=value sampleType=GAUGE\n", result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.haproxy.run_queue 1456156976840 0.0 addl1=foo host=r01n01 rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -247,8 +263,8 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put sys.haproxy.queue_current 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo proxy_name=proxy1 service_name=server1 sample=value sampleType=GAUGE\n",
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.haproxy.queue_current 1456156976840 0.0 addl1=foo host=r01n01 proxy_name=proxy1 rack=r01 sampleType=GAUGE service_name=server1\n",
|
||||
result);
|
||||
}
|
||||
|
||||
@@ -267,30 +283,104 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put sys.ethstat.tx_comp_queue_full 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo instance=eth0 sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.ethstat.tx_comp_queue_full 1456156976840 6.0 addl1=foo host=r01n01 instance=eth0 rack=r01 sampleType=GAUGE\n", result);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEthStatWithQueue() {
|
||||
public void testEthstatWithQueueStyle1() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("ethstat");
|
||||
vl.setPluginInstance("eth0");
|
||||
vl.setTime(TIME);
|
||||
vl.setType("derive");
|
||||
vl.setTypeInstance("rx_queue_1_bytes");
|
||||
vl.setTypeInstance("rx_queue_15_bytes");
|
||||
vl.setValues(Collections.singletonList((Number) 6.0D));
|
||||
DataSet ds = new DataSet("DERIVE");
|
||||
ds.addDataSource(new DataSource("value", 1, 6.0D, 100.0D));
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put sys.ethstat.rx_bytes 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo queue=1 instance=eth0 sample=value sampleType=GAUGE\n", result);
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.ethstat.rx_queue_bytes 1456156976840 6.0 addl1=foo host=r01n01 instance=eth0 queue=15 rack=r01 sampleType=GAUGE\n", result);
|
||||
|
||||
result = null;
|
||||
vl.setTypeInstance("queue_7_tx_bytes");
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.ethstat.queue_tx_bytes 1456156976840 6.0 addl1=foo host=r01n01 instance=eth0 queue=7 rack=r01 sampleType=GAUGE\n", result);
|
||||
|
||||
result = null;
|
||||
vl.setTypeInstance("queue_7_rx_xdp_drop");
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.ethstat.queue_rx_xdp_drop 1456156976840 6.0 addl1=foo host=r01n01 instance=eth0 queue=7 rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEthstatWithQueueStyle2() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("ethstat");
|
||||
vl.setPluginInstance("eth0");
|
||||
vl.setTime(TIME);
|
||||
vl.setType("derive");
|
||||
vl.setTypeInstance("rx-15.bytes");
|
||||
vl.setValues(Collections.singletonList((Number) 6.0D));
|
||||
DataSet ds = new DataSet("DERIVE");
|
||||
ds.addDataSource(new DataSource("value", 1, 6.0D, 100.0D));
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.ethstat.rx_queue_bytes 1456156976840 6.0 addl1=foo host=r01n01 instance=eth0 queue=15 rack=r01 sampleType=GAUGE\n", result);
|
||||
|
||||
result = null;
|
||||
vl.setTypeInstance("tx15_xdp_err");
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.ethstat.tx_queue_xdp_err 1456156976840 6.0 addl1=foo host=r01n01 instance=eth0 queue=15 rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEthstatWithTrafficClass() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("ethstat");
|
||||
vl.setPluginInstance("eth0");
|
||||
vl.setTime(TIME);
|
||||
vl.setType("derive");
|
||||
vl.setTypeInstance("veb.tc_15_tx_bytes");
|
||||
vl.setValues(Collections.singletonList((Number) 6.0D));
|
||||
DataSet ds = new DataSet("DERIVE");
|
||||
ds.addDataSource(new DataSource("value", 1, 6.0D, 100.0D));
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.ethstat.veb.tc_tx_bytes 1456156976840 6.0 addl1=foo host=r01n01 instance=eth0 rack=r01 sampleType=GAUGE trafficClass=15\n",
|
||||
result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEthstatWithChannel() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("ethstat");
|
||||
vl.setPluginInstance("eth0");
|
||||
vl.setTime(TIME);
|
||||
vl.setType("derive");
|
||||
vl.setTypeInstance("ch44_events");
|
||||
vl.setValues(Collections.singletonList((Number) 6.0D));
|
||||
DataSet ds = new DataSet("DERIVE");
|
||||
ds.addDataSource(new DataSource("value", 1, 6.0D, 100.0D));
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.ethstat.ch_events 1456156976840 6.0 addl1=foo channel=44 host=r01n01 instance=eth0 rack=r01 sampleType=GAUGE\n", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -307,10 +397,38 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl, null);
|
||||
assertEquals("put sys.ipmi.temperature 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo instance=LAN_NIC_Temp_system_board_(3.2) sample=value sampleType=GAUGE\n",
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.ipmi.temperature 1456156976840 6.0 addl1=foo host=r01n01 instance=LAN_NIC_Temp_system_board_(3.2) rack=r01 sampleType=GAUGE\n",
|
||||
result);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExclusions() {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("ethstat");
|
||||
vl.setPluginInstance("eth0");
|
||||
vl.setTime(TIME);
|
||||
vl.setType("derive");
|
||||
vl.setTypeInstance("rx_queue_1_bytes");
|
||||
vl.setValues(Collections.singletonList((Number) 6.0D));
|
||||
DataSet ds = new DataSet("DERIVE");
|
||||
ds.addDataSource(new DataSource("value", 1, 6.0D, 100.0D));
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
URL filteredMetricsFile = getClass().getClassLoader().getResource("filteredMetrics.txt");
|
||||
test.setFilteredMetricsFile(filteredMetricsFile.getPath());
|
||||
URL filteredTagsFile = getClass().getClassLoader().getResource("filteredTags.txt");
|
||||
test.setFilteredTagsFile(filteredTagsFile.getPath());
|
||||
|
||||
test.write(new MetricData(vl));
|
||||
assertEquals("put sys.ethstat.rx_queue_bytes 1456156976840 6.0 addl1=foo host=r01n01 queue=1 rack=r01\n", result);
|
||||
|
||||
result = null;
|
||||
vl.setPlugin("interface");
|
||||
vl.setTypeInstance("if_octets");
|
||||
assertNull(result);
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -21,12 +21,9 @@ import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
import net.jcip.annotations.NotThreadSafe;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({Collectd.class})
|
||||
@NotThreadSafe
|
||||
@PowerMockIgnore("javax.management.*")
|
||||
@PowerMockIgnore({"javax.management.*", "jdk.internal.reflect.*"})
|
||||
public class WriteTimelyPluginTest {
|
||||
|
||||
private WriteTimelyPlugin plugin = null;
|
||||
@@ -0,0 +1,3 @@
|
||||
sys.ethstat.*_to_.*
|
||||
sys.interface.if_packets
|
||||
sys.interface.if_octets
|
||||
@@ -0,0 +1,3 @@
|
||||
sys.interface.if_packets sampleType,instance
|
||||
sys.interface.if_octets sampleType,instance
|
||||
sys.ethstat.rx_queue_bytes sampleType,instance
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>2.1.4-SNAPSHOT</version>
|
||||
<version>2.2.3</version>
|
||||
</parent>
|
||||
<artifactId>timely-common</artifactId>
|
||||
<dependencies>
|
||||
|
||||
@@ -1,10 +1,63 @@
|
||||
package timely.api.request;
|
||||
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.util.ReferenceCounted;
|
||||
|
||||
public interface HttpRequest extends Request {
|
||||
public interface HttpRequest extends Request, ReferenceCounted {
|
||||
|
||||
public void setHttpRequest(FullHttpRequest httpRequest);
|
||||
|
||||
public FullHttpRequest getHttpRequest();
|
||||
|
||||
default int refCnt() {
|
||||
if (getHttpRequest() != null) {
|
||||
return getHttpRequest().refCnt();
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
default ReferenceCounted retain() {
|
||||
if (getHttpRequest() != null) {
|
||||
getHttpRequest().retain();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
default ReferenceCounted retain(int increment) {
|
||||
if (getHttpRequest() != null) {
|
||||
getHttpRequest().retain(increment);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
default ReferenceCounted touch() {
|
||||
if (getHttpRequest() != null) {
|
||||
getHttpRequest().touch();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
default ReferenceCounted touch(Object hint) {
|
||||
if (getHttpRequest() != null) {
|
||||
getHttpRequest().touch(hint);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
default boolean release() {
|
||||
if (getHttpRequest() != null) {
|
||||
return getHttpRequest().release();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
default boolean release(int decrement) {
|
||||
if (getHttpRequest() != null) {
|
||||
return getHttpRequest().release(decrement);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ public class QueryRequest extends AuthenticatedRequest implements HttpGetRequest
|
||||
private boolean counter = false;
|
||||
private long counterMax = 0;
|
||||
private long resetValue = 0;
|
||||
private Optional<String> interval = Optional.empty();
|
||||
private String interval = null;
|
||||
|
||||
public RateOption() {}
|
||||
|
||||
@@ -85,11 +85,11 @@ public class QueryRequest extends AuthenticatedRequest implements HttpGetRequest
|
||||
this.resetValue = resetValue;
|
||||
}
|
||||
|
||||
public Optional<String> getInterval() {
|
||||
public String getInterval() {
|
||||
return interval;
|
||||
}
|
||||
|
||||
public void setInterval(Optional<String> interval) {
|
||||
public void setInterval(String interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ public class QueryRequest extends AuthenticatedRequest implements HttpGetRequest
|
||||
private String aggregator;
|
||||
private String metric;
|
||||
private boolean rate = false;
|
||||
private RateOption rateOptions = null;
|
||||
private RateOption rateOptions = new RateOption();
|
||||
private Optional<String> downsample = Optional.empty();
|
||||
private Map<String,String> tags = new LinkedHashMap<>();
|
||||
private Collection<Filter> filters = new ArrayList<>();
|
||||
@@ -547,7 +547,7 @@ public class QueryRequest extends AuthenticatedRequest implements HttpGetRequest
|
||||
options.setCounter(rateOptions[x].endsWith("counter"));
|
||||
break;
|
||||
case 1:
|
||||
options.setInterval(Optional.of(rateOptions[x]));
|
||||
options.setInterval(rateOptions[x]);
|
||||
break;
|
||||
case 2:
|
||||
options.setCounterMax(Long.parseLong(rateOptions[x]));
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package timely.api.response;
|
||||
|
||||
public class StrictTransportResponse {
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package timely.common.configuration;
|
||||
|
||||
import static org.apache.accumulo.core.conf.ConfigurationTypeHelper.getTimeInMillis;
|
||||
|
||||
import org.apache.accumulo.core.client.Accumulo;
|
||||
import org.apache.accumulo.core.client.AccumuloClient;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
@@ -16,7 +18,13 @@ public class AccumuloConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public AccumuloClient accumuloClient(AccumuloProperties accumuloProperties, ZookeeperProperties zookeeperProperties) {
|
||||
return Accumulo.newClient().to(accumuloProperties.getInstanceName(), zookeeperProperties.getServers())
|
||||
.as(accumuloProperties.getUsername(), accumuloProperties.getPassword()).build();
|
||||
// @formatter:off
|
||||
return Accumulo.newClient()
|
||||
.to(accumuloProperties.getInstanceName(), zookeeperProperties.getServers())
|
||||
.as(accumuloProperties.getUsername(), accumuloProperties.getPassword())
|
||||
.batchScannerQueryThreads(accumuloProperties.getScan().getThreads())
|
||||
.zkTimeout(Long.valueOf(getTimeInMillis(zookeeperProperties.getTimeout())).intValue())
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ public class HttpProperties {
|
||||
private Integer basePort;
|
||||
@NotNull
|
||||
private String host;
|
||||
private String redirectPath = "/secure-me";
|
||||
private long strictTransportMaxAge = 604800;
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
@@ -58,14 +57,6 @@ public class HttpProperties {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getRedirectPath() {
|
||||
return redirectPath;
|
||||
}
|
||||
|
||||
public void setRedirectPath(String redirectPath) {
|
||||
this.redirectPath = redirectPath;
|
||||
}
|
||||
|
||||
public long getStrictTransportMaxAge() {
|
||||
return strictTransportMaxAge;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,7 @@ public class SslServerProperties implements SslProperties {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SslServerProperties.class);
|
||||
|
||||
private String[] ciphers = new String[] {"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"};
|
||||
private String[] ciphers = new String[] {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"};
|
||||
private String[] enabledProtocols;
|
||||
private String keyStoreType;
|
||||
private String keyStoreFile;
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package timely.common.configuration;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import timely.util.Exclusions;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({AccumuloProperties.class, CacheProperties.class, CorsProperties.class, HttpProperties.class, MetaCacheProperties.class,
|
||||
RestClientProperties.class, ScanProperties.class, SecurityProperties.class, ServerProperties.class, SslClientProperties.class,
|
||||
@@ -10,4 +14,15 @@ import org.springframework.context.annotation.Configuration;
|
||||
|
||||
public class TimelyCommonConfiguration {
|
||||
|
||||
@Bean
|
||||
public Exclusions exclusions(TimelyProperties timelyProperties) {
|
||||
Exclusions exclusions = new Exclusions();
|
||||
if (StringUtils.isNotBlank(timelyProperties.getFilteredMetricsFile())) {
|
||||
exclusions.setFilteredMetricsFile(timelyProperties.getFilteredMetricsFile());
|
||||
}
|
||||
if (StringUtils.isNotBlank(timelyProperties.getFilteredTagsFile())) {
|
||||
exclusions.setFilteredTagsFile(timelyProperties.getFilteredTagsFile());
|
||||
}
|
||||
return exclusions;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,9 @@ public class TimelyProperties {
|
||||
private int instance = 1;
|
||||
private int portIncrement = 100;
|
||||
private String defaultVisibility = null;
|
||||
private int tagFilterCacheSize = 10000;
|
||||
private String filteredMetricsFile = null;
|
||||
private String filteredTagsFile = null;
|
||||
|
||||
public boolean isTest() {
|
||||
return test;
|
||||
@@ -91,4 +94,28 @@ public class TimelyProperties {
|
||||
this.metricsReportIgnoredTags = metricsReportIgnoredTags;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setTagFilterCacheSize(int tagFilterCacheSize) {
|
||||
this.tagFilterCacheSize = tagFilterCacheSize;
|
||||
}
|
||||
|
||||
public int getTagFilterCacheSize() {
|
||||
return tagFilterCacheSize;
|
||||
}
|
||||
|
||||
public void setFilteredMetricsFile(String filteredMetricsFile) {
|
||||
this.filteredMetricsFile = filteredMetricsFile;
|
||||
}
|
||||
|
||||
public String getFilteredMetricsFile() {
|
||||
return filteredMetricsFile;
|
||||
}
|
||||
|
||||
public void setFilteredTagsFile(String filteredTagsFile) {
|
||||
this.filteredTagsFile = filteredTagsFile;
|
||||
}
|
||||
|
||||
public String getFilteredTagsFile() {
|
||||
return filteredTagsFile;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
@@ -90,7 +91,7 @@ public class Tag implements Comparable<Tag>, Serializable {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.toString().hashCode();
|
||||
return new HashCodeBuilder().append(this.key).append(this.value).toHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import timely.model.Tag;
|
||||
|
||||
@@ -24,9 +25,7 @@ public class TagListParser implements Parser<List<Tag>>, Combiner<Collection<Tag
|
||||
if (!p.isEmpty()) {
|
||||
Tag tag = tagParser.parse(p);
|
||||
// unescape commas in the key and value of the tag
|
||||
tag.setKey(tag.getKey().replaceAll("\\\\,", ","));
|
||||
tag.setValue(tag.getValue().replaceAll("\\\\,", ","));
|
||||
tags.add(tag);
|
||||
tags.add(unescapeCommas(tag));
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
@@ -36,7 +35,9 @@ public class TagListParser implements Parser<List<Tag>>, Combiner<Collection<Tag
|
||||
public String combine(Collection<Tag> tags) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (!tags.isEmpty()) {
|
||||
tags.forEach(p -> builder.append(tagParser.combine(p)).append(','));
|
||||
tags.forEach(p -> {
|
||||
builder.append(tagParser.combine(escapeCommas(p))).append(',');
|
||||
});
|
||||
builder.setLength(builder.length() - 1);
|
||||
}
|
||||
return builder.toString();
|
||||
@@ -48,11 +49,26 @@ public class TagListParser implements Parser<List<Tag>>, Combiner<Collection<Tag
|
||||
* @return string representation
|
||||
*/
|
||||
public String combine(Map<String,String> tags) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (!tags.isEmpty()) {
|
||||
tags.forEach((k, v) -> builder.append(tagParser.combine(new Tag(k, v))).append(','));
|
||||
builder.setLength(builder.length() - 1);
|
||||
}
|
||||
return builder.toString();
|
||||
return combine(tags.entrySet().stream().map(e -> new Tag(e.getKey(), e.getValue())).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private Tag escapeCommas(Tag tag) {
|
||||
return escapeCommas(tag.getKey(), tag.getValue());
|
||||
}
|
||||
|
||||
private Tag escapeCommas(String k, String v) {
|
||||
k = k.replaceAll(",", "\\\\,");
|
||||
v = v.replaceAll(",", "\\\\,");
|
||||
return new Tag(k, v);
|
||||
}
|
||||
|
||||
private Tag unescapeCommas(Tag tag) {
|
||||
return unescapeCommas(tag.getKey(), tag.getValue());
|
||||
}
|
||||
|
||||
private Tag unescapeCommas(String k, String v) {
|
||||
k = k.replaceAll("\\\\,", ",");
|
||||
v = v.replaceAll("\\\\,", ",");
|
||||
return new Tag(k, v);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package timely.netty;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String ERR_WRITING_RESPONSE = "Error writing response to pipeline: {}";
|
||||
public static final String ERR_WRITING_RESPONSE = "Error writing response to pipeline: %s";
|
||||
public static final String TEXT_TYPE = "text/plain";
|
||||
public static final String HTML_TYPE = "text/html";
|
||||
public static final String JSON_TYPE = "application/json";
|
||||
|
||||
@@ -27,7 +27,6 @@ import timely.api.request.AuthenticatedRequest;
|
||||
import timely.api.request.HttpGetRequest;
|
||||
import timely.api.request.HttpPostRequest;
|
||||
import timely.api.request.HttpRequest;
|
||||
import timely.api.response.StrictTransportResponse;
|
||||
import timely.api.response.TimelyException;
|
||||
import timely.auth.SubjectIssuerDNPair;
|
||||
import timely.auth.TimelyAuthenticationToken;
|
||||
@@ -45,13 +44,11 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
|
||||
private static final String LOG_PARSED_REQUEST = "Parsed request {}";
|
||||
|
||||
protected SecurityProperties securityProperties;
|
||||
private final String nonSecureRedirectAddress;
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
public HttpRequestDecoder(AuthenticationService authenticationService, SecurityProperties securityProperties, HttpProperties httpProperties) {
|
||||
|
||||
this.securityProperties = securityProperties;
|
||||
this.nonSecureRedirectAddress = httpProperties.getRedirectPath();
|
||||
this.authenticationService = authenticationService;
|
||||
}
|
||||
|
||||
@@ -82,11 +79,6 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
|
||||
|
||||
final String uri = msg.uri();
|
||||
final QueryStringDecoder decoder = new QueryStringDecoder(uri);
|
||||
if (decoder.path().equals(nonSecureRedirectAddress)) {
|
||||
out.add(new StrictTransportResponse());
|
||||
return;
|
||||
}
|
||||
|
||||
final String sessionId = getSessionId(msg);
|
||||
log.trace("SessionID: " + sessionId);
|
||||
|
||||
|
||||
@@ -1,385 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project 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 timely.netty.http;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CACHE_CONTROL;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.DATE;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.EXPIRES;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.IF_MODIFIED_SINCE;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.LAST_MODIFIED;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.LOCATION;
|
||||
import static io.netty.handler.codec.http.HttpMethod.GET;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.FOUND;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_MODIFIED;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.DefaultHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpChunkedInput;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http.HttpResponse;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpUtil;
|
||||
import io.netty.handler.stream.ChunkedFile;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
import timely.netty.Constants;
|
||||
|
||||
/**
|
||||
* A simple handler that serves incoming HTTP requests to send their respective HTTP responses. It also implements {@code 'If-Modified-Since'} header to take
|
||||
* advantage of browser cache, as described in <a href="http://tools.ietf.org/html/rfc2616#section-14.25">RFC 2616</a>.
|
||||
*
|
||||
* <h3>How Browser Caching Works</h3>
|
||||
*
|
||||
* Web browser caching works with HTTP headers as illustrated by the following sample:
|
||||
* <ol>
|
||||
* <li>Request #1 returns the content of {@code /file1.txt}.</li>
|
||||
* <li>Contents of {@code /file1.txt} is cached by the browser.</li>
|
||||
* <li>Request #2 for {@code /file1.txt} does return the contents of the file again. Rather, a 304 Not Modified is returned. This tells the browser to use the
|
||||
* contents stored in its cache.</li>
|
||||
* <li>The server knows the file has not been modified because the {@code If-Modified-Since} date is the same as the file's last modified date.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <pre>
|
||||
* Request #1 Headers
|
||||
* ===================
|
||||
* GET /file1.txt HTTP/1.1
|
||||
*
|
||||
* Response #1 Headers
|
||||
* ===================
|
||||
* HTTP/1.1 200 OK
|
||||
* Date: Tue, 01 Mar 2011 22:44:26 GMT
|
||||
* Last-Modified: Wed, 30 Jun 2010 21:36:48 GMT
|
||||
* Expires: Tue, 01 Mar 2012 22:44:26 GMT
|
||||
* Cache-Control: private, max-age=31536000
|
||||
*
|
||||
* Request #2 Headers
|
||||
* ===================
|
||||
* GET /file1.txt HTTP/1.1
|
||||
* If-Modified-Since: Wed, 30 Jun 2010 21:36:48 GMT
|
||||
*
|
||||
* Response #2 Headers
|
||||
* ===================
|
||||
* HTTP/1.1 304 Not Modified
|
||||
* Date: Tue, 01 Mar 2011 22:44:28 GMT
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> implements TimelyHttpHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HttpStaticFileServerHandler.class);
|
||||
public static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
|
||||
public static final String HTTP_DATE_GMT_TIMEZONE = "GMT";
|
||||
public static final int HTTP_CACHE_SECONDS = 60;
|
||||
private boolean ignoreSslHandshakeErrors = false;
|
||||
|
||||
@Override
|
||||
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
|
||||
if (!request.decoderResult().isSuccess()) {
|
||||
sendError(ctx, BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.method() != GET) {
|
||||
sendError(ctx, METHOD_NOT_ALLOWED);
|
||||
return;
|
||||
}
|
||||
|
||||
String uri = request.uri();
|
||||
if (uri.startsWith("/favicon.ico")) {
|
||||
uri = uri.replaceFirst("\\/", "/webapp/");
|
||||
}
|
||||
|
||||
if (!uri.startsWith("/webapp")) {
|
||||
sendError(ctx, FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
final String path = sanitizeUri(uri);
|
||||
if (path == null) {
|
||||
sendError(ctx, FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
log.trace("Looking for requested file at: " + path);
|
||||
|
||||
File file = new File(path);
|
||||
if (file.isHidden() || !file.exists()) {
|
||||
sendError(ctx, NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.isDirectory()) {
|
||||
if (uri.endsWith("/")) {
|
||||
sendListing(ctx, file);
|
||||
} else {
|
||||
sendRedirect(ctx, uri + '/');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.isFile()) {
|
||||
sendError(ctx, FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache Validation
|
||||
String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE);
|
||||
if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) {
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
|
||||
Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince);
|
||||
|
||||
// Only compare up to the second because the datetime format we send
|
||||
// to the client
|
||||
// does not have milliseconds
|
||||
long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000;
|
||||
long fileLastModifiedSeconds = file.lastModified() / 1000;
|
||||
if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) {
|
||||
sendNotModified(ctx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RandomAccessFile raf;
|
||||
try {
|
||||
raf = new RandomAccessFile(file, "r");
|
||||
} catch (FileNotFoundException ignore) {
|
||||
sendError(ctx, NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
long fileLength = raf.length();
|
||||
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||
HttpUtil.setContentLength(response, fileLength);
|
||||
setContentTypeHeader(response, file);
|
||||
setDateAndCacheHeaders(response, file);
|
||||
HttpUtil.setTransferEncodingChunked(response, true);
|
||||
if (HttpUtil.isKeepAlive(request)) {
|
||||
response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||
}
|
||||
|
||||
// Write the initial line and the header.
|
||||
sendResponse(ctx, response);
|
||||
log.trace("Returning {}", response);
|
||||
|
||||
// Write the content.
|
||||
sendResponse(ctx, new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
// ignore SSLHandshakeException when using a self-signed server certificate
|
||||
if (ignoreSslHandshakeErrors && cause.getCause() instanceof SSLHandshakeException) {
|
||||
return;
|
||||
}
|
||||
log.error("Error serving file", cause);
|
||||
if (ctx.channel().isActive()) {
|
||||
sendError(ctx, INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Pattern INSECURE_URI = Pattern.compile(".*[<>&\"].*");
|
||||
|
||||
private static String sanitizeUri(String uri) {
|
||||
// Decode the path.
|
||||
try {
|
||||
uri = URLDecoder.decode(uri, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
|
||||
if (uri.isEmpty() || uri.charAt(0) != '/') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Convert file separators.
|
||||
uri = uri.replace('/', File.separatorChar);
|
||||
|
||||
// Simplistic dumb security check.
|
||||
// You will have to do something serious in the production environment.
|
||||
if (uri.contains(File.separator + '.') || uri.contains('.' + File.separator) || uri.charAt(0) == '.' || uri.charAt(uri.length() - 1) == '.'
|
||||
|| INSECURE_URI.matcher(uri).matches()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Convert to absolute path.
|
||||
return SystemPropertyUtil.get("user.dir") + File.separator + uri;
|
||||
}
|
||||
|
||||
private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[A-Za-z0-9][-_A-Za-z0-9\\.]*");
|
||||
|
||||
private static void sendListing(ChannelHandlerContext ctx, File dir) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK);
|
||||
response.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
|
||||
String dirPath = dir.getPath();
|
||||
StringBuilder buf = new StringBuilder().append("<!DOCTYPE html>\r\n").append("<html><head><title>").append("Listing of: ").append(dirPath)
|
||||
.append("</title></head><body>\r\n")
|
||||
|
||||
.append("<h3>Listing of: ").append(dirPath).append("</h3>\r\n")
|
||||
|
||||
.append("<ul>").append("<li><a href=\"../\">..</a></li>\r\n");
|
||||
|
||||
File[] files = dir.listFiles();
|
||||
if (null != files) {
|
||||
for (File f : files) {
|
||||
if (f.isHidden() || !f.canRead()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = f.getName();
|
||||
if (!ALLOWED_FILE_NAME.matcher(name).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buf.append("<li><a href=\"").append(name).append("\">").append(name).append("</a></li>\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
buf.append("</ul></body></html>\r\n");
|
||||
ByteBuf buffer = Unpooled.copiedBuffer(buf, CharsetUtil.UTF_8);
|
||||
response.content().writeBytes(buffer);
|
||||
buffer.release();
|
||||
|
||||
// Close the connection as soon as the error message is sent.
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
log.trace(Constants.LOG_RETURNING_RESPONSE, response);
|
||||
}
|
||||
|
||||
private static void sendRedirect(ChannelHandlerContext ctx, String newUri) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, FOUND);
|
||||
response.headers().set(LOCATION, newUri);
|
||||
|
||||
// Close the connection as soon as the error message is sent.
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
log.trace(Constants.LOG_RETURNING_RESPONSE, response);
|
||||
}
|
||||
|
||||
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status + "\r\n", CharsetUtil.UTF_8));
|
||||
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
|
||||
// Close the connection as soon as the error message is sent.
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
log.trace(Constants.LOG_RETURNING_RESPONSE, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* When file timestamp is the same as what the browser is sending up, send a "304 Not Modified"
|
||||
*
|
||||
* @param ctx
|
||||
* Context
|
||||
*/
|
||||
private static void sendNotModified(ChannelHandlerContext ctx) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, NOT_MODIFIED);
|
||||
setDateHeader(response);
|
||||
|
||||
// Close the connection as soon as the error message is sent.
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
log.trace(Constants.LOG_RETURNING_RESPONSE, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Date header for the HTTP response
|
||||
*
|
||||
* @param response
|
||||
* HTTP response
|
||||
*/
|
||||
private static void setDateHeader(FullHttpResponse response) {
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
|
||||
dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));
|
||||
|
||||
Calendar time = new GregorianCalendar();
|
||||
response.headers().set(DATE, dateFormatter.format(time.getTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Date and Cache headers for the HTTP Response
|
||||
*
|
||||
* @param response
|
||||
* HTTP response
|
||||
* @param fileToCache
|
||||
* file to extract content type
|
||||
*/
|
||||
private static void setDateAndCacheHeaders(HttpResponse response, File fileToCache) {
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
|
||||
dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));
|
||||
|
||||
// Date header
|
||||
Calendar time = new GregorianCalendar();
|
||||
response.headers().set(DATE, dateFormatter.format(time.getTime()));
|
||||
|
||||
// Add cache headers
|
||||
time.add(Calendar.SECOND, HTTP_CACHE_SECONDS);
|
||||
response.headers().set(EXPIRES, dateFormatter.format(time.getTime()));
|
||||
response.headers().set(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);
|
||||
response.headers().set(LAST_MODIFIED, dateFormatter.format(new Date(fileToCache.lastModified())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content type header for the HTTP Response
|
||||
*
|
||||
* @param response
|
||||
* HTTP response
|
||||
* @param file
|
||||
* file to extract content type
|
||||
*/
|
||||
private static void setContentTypeHeader(HttpResponse response, File file) {
|
||||
MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
|
||||
response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));
|
||||
}
|
||||
|
||||
public HttpStaticFileServerHandler setIgnoreSslHandshakeErrors(boolean ignoreSslHandshakeErrors) {
|
||||
this.ignoreSslHandshakeErrors = ignoreSslHandshakeErrors;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package timely.netty.http;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOutboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.handler.codec.http.HttpResponse;
|
||||
import timely.common.configuration.HttpProperties;
|
||||
|
||||
public class HttpStrictTransportSecurityHandler extends ChannelOutboundHandlerAdapter {
|
||||
|
||||
public static final String HSTS_HEADER_NAME = "Strict-Transport-Security";
|
||||
private final String HSTS_HEADER_VALUE;
|
||||
|
||||
public HttpStrictTransportSecurityHandler(HttpProperties httpProperties) {
|
||||
this.HSTS_HEADER_VALUE = String.format("max-age=%d; includeSubDomains; preload", httpProperties.getStrictTransportMaxAge());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
// Check if the connection is SSL/TLS encrypted
|
||||
boolean isHttps = ctx.channel().pipeline().get(io.netty.handler.ssl.SslHandler.class) != null;
|
||||
if (isHttps && msg instanceof HttpResponse) {
|
||||
HttpResponse response = (HttpResponse) msg;
|
||||
// Add the HSTS header only if it isn't already present
|
||||
if (!response.headers().contains(HSTS_HEADER_NAME)) {
|
||||
response.headers().set(HSTS_HEADER_NAME, HSTS_HEADER_VALUE);
|
||||
}
|
||||
}
|
||||
// Forward the message to the next handler in the pipeline
|
||||
super.write(ctx, msg, promise);
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
package timely.server.netty.http;
|
||||
package timely.netty.http;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@@ -12,7 +12,6 @@ import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import timely.api.request.VersionRequest;
|
||||
import timely.netty.Constants;
|
||||
import timely.netty.http.TimelyHttpHandler;
|
||||
|
||||
public class HttpVersionRequestHandler extends SimpleChannelInboundHandler<VersionRequest> implements TimelyHttpHandler {
|
||||
|
||||
+4
-11
@@ -9,7 +9,6 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
@@ -18,17 +17,12 @@ import io.netty.handler.ssl.SslContext;
|
||||
import timely.common.configuration.HttpProperties;
|
||||
import timely.netty.Constants;
|
||||
|
||||
public class NonSslRedirectHandler extends OptionalSslHandler implements TimelyHttpHandler {
|
||||
public class NonSslForbiddenHandler extends OptionalSslHandler implements TimelyHttpHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(NonSslRedirectHandler.class);
|
||||
private final String redirectAddress;
|
||||
private static final Logger log = LoggerFactory.getLogger(NonSslForbiddenHandler.class);
|
||||
|
||||
public NonSslRedirectHandler(HttpProperties httpProperties, SslContext sslContext) {
|
||||
public NonSslForbiddenHandler(HttpProperties httpProperties, SslContext sslContext) {
|
||||
super(sslContext);
|
||||
String timelyHost = httpProperties.getHost();
|
||||
int timelyPort = httpProperties.getPort();
|
||||
String path = httpProperties.getRedirectPath();
|
||||
redirectAddress = "https://" + timelyHost + ":" + timelyPort + path;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,8 +44,7 @@ public class NonSslRedirectHandler extends OptionalSslHandler implements TimelyH
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
log.trace("Received non-SSL request, returning redirect");
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.MOVED_PERMANENTLY, Unpooled.EMPTY_BUFFER);
|
||||
response.headers().set(HttpHeaderNames.LOCATION, redirectAddress);
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.FORBIDDEN, Unpooled.EMPTY_BUFFER);
|
||||
log.trace(Constants.LOG_RETURNING_RESPONSE, response);
|
||||
encoder.write(ctx, response, ctx.voidPromise());
|
||||
ctx.flush();
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project 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 timely.netty.http;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import timely.netty.Constants;
|
||||
|
||||
public class NotFoundHandler extends SimpleChannelInboundHandler<FullHttpRequest> implements TimelyHttpHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(NotFoundHandler.class);
|
||||
|
||||
@Override
|
||||
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
|
||||
// if the request reaches this handler, it means that no other handler has processed it, so we return a 404 Not Found response
|
||||
sendError(ctx, NOT_FOUND);
|
||||
}
|
||||
|
||||
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status + "\r\n", CharsetUtil.UTF_8));
|
||||
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
|
||||
// Close the connection as soon as the error message is sent.
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
log.trace(Constants.LOG_RETURNING_RESPONSE, response);
|
||||
}
|
||||
}
|
||||
@@ -23,21 +23,27 @@ public interface TimelyHttpHandler {
|
||||
Logger log = LoggerFactory.getLogger(TimelyHttpHandler.class);
|
||||
|
||||
default void sendHttpError(ChannelHandlerContext ctx, TimelyException e) throws JsonProcessingException {
|
||||
log.error("Error in pipeline, response code: {}, message: {}", e.getCode(), e.getMessage());
|
||||
byte[] buf = JsonUtil.getObjectMapper().writeValueAsBytes(new TimelyExceptionResponse(e));
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(e.getCode()), Unpooled.copiedBuffer(buf));
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
e.getResponseHeaders().entrySet().forEach(entry -> response.headers().set(entry.getKey(), entry.getValue()));
|
||||
// Send the error response
|
||||
sendResponse(ctx, response);
|
||||
try {
|
||||
log.error("Error in pipeline, response code: {}, message: {}", e.getCode(), e.getMessage());
|
||||
byte[] buf = JsonUtil.getObjectMapper().writeValueAsBytes(new TimelyExceptionResponse(e));
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(e.getCode()), Unpooled.copiedBuffer(buf));
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
e.getResponseHeaders().entrySet().forEach(entry -> response.headers().set(entry.getKey(), entry.getValue()));
|
||||
// Send the error response
|
||||
sendResponse(ctx, response);
|
||||
} catch (Exception ex) {
|
||||
log.error(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
default void sendResponse(ChannelHandlerContext ctx, Object msg) {
|
||||
ChannelFuture f = ctx.writeAndFlush(msg);
|
||||
ChannelFuture cf = ctx.writeAndFlush(msg);
|
||||
log.trace(Constants.LOG_RETURNING_RESPONSE, msg);
|
||||
if (!f.isSuccess()) {
|
||||
log.error(Constants.ERR_WRITING_RESPONSE, f.cause());
|
||||
if (!cf.isSuccess()) {
|
||||
Throwable t = cf.cause();
|
||||
String message = (t == null) ? "" : t.getMessage();
|
||||
log.error(String.format(Constants.ERR_WRITING_RESPONSE, message), cf.cause());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
package timely.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import timely.model.Metric;
|
||||
import timely.model.Tag;
|
||||
import timely.model.parse.MetricParser;
|
||||
|
||||
public class Exclusions {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(Exclusions.class);
|
||||
private static final MetricParser metricParser = new MetricParser();
|
||||
private List<String> filteredMetrics = new ArrayList<>();
|
||||
private Map<String,Set<String>> filteredTags = new LinkedHashMap<>();
|
||||
|
||||
public interface LineHandler {
|
||||
void handleLine(String line);
|
||||
}
|
||||
|
||||
public void readFile(String file, LineHandler lineHandler) {
|
||||
File f = new File(file);
|
||||
if (f.exists() && f.isFile() && f.canRead()) {
|
||||
try (InputStream iStream = new FileInputStream(f);
|
||||
InputStreamReader streamReader = new InputStreamReader(iStream, StandardCharsets.UTF_8);
|
||||
BufferedReader reader = new BufferedReader(streamReader)) {
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
try {
|
||||
lineHandler.handleLine(line);
|
||||
} catch (Exception e) {
|
||||
log.error(MessageFormat.format("Error reading line {0}", line), e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error(MessageFormat.format("Error reading file {0}", file), e);
|
||||
}
|
||||
} else {
|
||||
log.error(MessageFormat.format("File ''{0}'' either does not exist or is not readable", file));
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getFilteredMetrics(String filteredMetricsFile) {
|
||||
List<String> filteredMetricRegexes = new ArrayList<>();
|
||||
readFile(filteredMetricsFile, (line) -> {
|
||||
if (!line.endsWith(".*")) {
|
||||
line = line + ".*";
|
||||
}
|
||||
filteredMetricRegexes.add(line);
|
||||
});
|
||||
return filteredMetricRegexes;
|
||||
}
|
||||
|
||||
public Map<String,Set<String>> getFilteredTags(String filteredTagsFile) {
|
||||
Map<String,Set<String>> filteredTagsForMetrics = new LinkedHashMap<>();
|
||||
readFile(filteredTagsFile, (line) -> {
|
||||
int x = line.indexOf(" ");
|
||||
String metric = line.substring(0, x);
|
||||
String tags = line.substring(x + 1).trim();
|
||||
Set<String> tagSet = Arrays.stream(tags.split(",")).map(tag -> tag.trim()).collect(Collectors.toSet());
|
||||
filteredTagsForMetrics.put(metric, tagSet);
|
||||
});
|
||||
return filteredTagsForMetrics;
|
||||
}
|
||||
|
||||
public void setFilteredMetricsFile(String filteredMetricsFile) {
|
||||
this.filteredMetrics = getFilteredMetrics(filteredMetricsFile);
|
||||
}
|
||||
|
||||
public void setFilteredTagsFile(String filteredTagsFile) {
|
||||
this.filteredTags = getFilteredTags(filteredTagsFile);
|
||||
}
|
||||
|
||||
// format put metric timestamp value tag1=value1 tag2=value2 tag3=value3
|
||||
// where the tags are sorted
|
||||
public boolean filterMetric(String metricPutLine) {
|
||||
String metricLine = buildMetricLine(metricPutLine);
|
||||
for (String filteredRegex : filteredMetrics) {
|
||||
if (metricLine.matches(filteredRegex)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean filterMetric(Metric metric) {
|
||||
String metricLine = buildMetricLine(metric);
|
||||
for (String filteredRegex : filteredMetrics) {
|
||||
if (metricLine.matches(filteredRegex)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected String buildMetricLine(String metricPutLine) {
|
||||
Metric metric = metricParser.parse(metricPutLine);
|
||||
return buildMetricLine(metric);
|
||||
}
|
||||
|
||||
protected String buildMetricLine(Metric metric) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(metric.getName()).append(" ");
|
||||
metric.getTags().stream().forEach(t -> sb.append(t.join()).append(" "));
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
public String filterExcludedTags(String metricLineOrig) {
|
||||
if (filteredTags.isEmpty()) {
|
||||
return metricLineOrig;
|
||||
}
|
||||
Metric metric = metricParser.parse(metricLineOrig);
|
||||
filterExcludedTags(metric);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("put ");
|
||||
sb.append(metric.getName()).append(" ");
|
||||
sb.append(metric.getValue().getTimestamp()).append(" ");
|
||||
sb.append(metric.getValue().getMeasure()).append(" ");
|
||||
metric.getTags().stream().forEach(t -> sb.append(t.join()).append(" "));
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
public void filterExcludedTags(Metric metric) {
|
||||
if (!filteredTags.isEmpty()) {
|
||||
Set<String> tags = filteredTags.get(metric.getName());
|
||||
if (tags != null && !tags.isEmpty()) {
|
||||
List<Tag> filteredTags = metric.getTags().stream().filter(t -> !tags.contains(t.getKey())).collect(Collectors.toList());
|
||||
metric.setTags(filteredTags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package timely.util;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ExclusionTest {
|
||||
|
||||
@Test
|
||||
public void testLoadFilteredMetricsFile() {
|
||||
Exclusions exclusions = new Exclusions();
|
||||
URL url = getClass().getClassLoader().getResource("filteredMetrics.txt");
|
||||
List<String> metricExclusions = exclusions.getFilteredMetrics(url.getFile());
|
||||
Assert.assertEquals(4, metricExclusions.size());
|
||||
System.out.println(metricExclusions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadFilteredTagsFile() {
|
||||
Exclusions exclusions = new Exclusions();
|
||||
URL url = getClass().getClassLoader().getResource("filteredTags.txt");
|
||||
Map<String,Set<String>> filteredTags = exclusions.getFilteredTags(url.getFile());
|
||||
Assert.assertEquals(2, filteredTags.size());
|
||||
System.out.println(filteredTags);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetricExclusions() {
|
||||
Exclusions exclusions = new Exclusions();
|
||||
URL filteredMetrics = getClass().getClassLoader().getResource("filteredMetrics.txt");
|
||||
URL filteredTags = getClass().getClassLoader().getResource("filteredTags.txt");
|
||||
exclusions.setFilteredMetricsFile(filteredMetrics.getFile());
|
||||
exclusions.setFilteredTagsFile(filteredTags.getFile());
|
||||
|
||||
String metric1 = "put sys.interface.if_octets 1740090590221 71838.0 host=localhost instance=veth88545ad sampleType=DERIVE";
|
||||
Assert.assertTrue(exclusions.filterMetric(metric1));
|
||||
String metric2 = "put sys.interface.if_errors 1740090590221 71838.0 host=localhost instance=veth88545ad sampleType=DERIVE";
|
||||
Assert.assertFalse(exclusions.filterMetric(metric2));
|
||||
Assert.assertEquals("put sys.interface.if_octets 1740090590221 71838.0 host=localhost", exclusions.filterExcludedTags(metric1));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
sys.ethstat.(tx|rx)[-]?[0-9]+[_.]
|
||||
sys.ethstat.*_to_.*
|
||||
sys.interface.if_packets
|
||||
sys.interface.if_octets
|
||||
@@ -0,0 +1,2 @@
|
||||
sys.interface.if_packets sampleType,instance
|
||||
sys.interface.if_octets sampleType,instance
|
||||
@@ -7,9 +7,9 @@
|
||||
</formats>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>timely-app/dist</directory>
|
||||
<outputDirectory>timely-app</outputDirectory>
|
||||
<directory>timely-datasource/dist</directory>
|
||||
<outputDirectory>timely-datasource</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
</assembly>
|
||||
</assembly>
|
||||
+2
-2
@@ -4,9 +4,9 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>2.1.4-SNAPSHOT</version>
|
||||
<version>2.2.3</version>
|
||||
</parent>
|
||||
<artifactId>timely-app</artifactId>
|
||||
<artifactId>timely-datasource</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
node_modules/
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
...require('@grafana/toolkit/src/config/prettier.plugin.config.json'),
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
//+build mage
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
// mage:import
|
||||
_ "github.com/grafana/grafana-plugin-sdk-go/build"
|
||||
)
|
||||
|
||||
// CheckCheck builds production back-end components.
|
||||
func CheckCheck() {
|
||||
fmt.Println("hello! TODO.... (the other commands are imported)")
|
||||
}
|
||||
|
||||
// Default configures the default target.
|
||||
var Default = CheckCheck
|
||||
@@ -1,6 +0,0 @@
|
||||
# Timely Data Source Plugin
|
||||
|
||||
Timely is a time series database application that provides secure access to time
|
||||
series data. Timely is written in Java, uses
|
||||
[Apache Accumulo](https://accumuloProperties.apache.org/) for backend storage, and has
|
||||
a configurable length memory cache.
|
||||
@@ -1,26 +0,0 @@
|
||||
# Test against the latest version of this Node.js version
|
||||
environment:
|
||||
nodejs_version: '10'
|
||||
|
||||
# Local NPM Modules
|
||||
cache:
|
||||
- node_modules
|
||||
|
||||
# Install scripts. (runs after repo cloning)
|
||||
install:
|
||||
# Get the latest stable version of Node.js or io.js
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
# install modules
|
||||
- npm install -g yarn --quiet
|
||||
- yarn install --pure-lockfile
|
||||
|
||||
# Post-install test scripts.
|
||||
test_script:
|
||||
# Output useful info for debugging.
|
||||
- node --version
|
||||
- npm --version
|
||||
|
||||
# Run the build
|
||||
build_script:
|
||||
- yarn dev # This will also run prettier!
|
||||
- yarn build # make sure both scripts work
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites name="jest tests" tests="1" failures="0" time="1.179">
|
||||
<testsuite name="placeholder test" errors="0" failures="0" skipped="0" timestamp="2021-10-22T20:15:17" time="0.552" tests="1">
|
||||
<testcase classname="placeholder test should return true" name="placeholder test should return true" time="0.003">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
# Timely Data Source Plugin
|
||||
|
||||
Timely is a time series database application that provides secure access to time
|
||||
series data. Timely is written in Java, uses
|
||||
[Apache Accumulo](https://accumulo.apache.org/) for backend storage, and has
|
||||
a configurable length memory cache.
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
define((function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=71)}({71:function(e,t,n){}})}));
|
||||
//# sourceMappingURL=dark.js.map
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"sources":["webpack:///webpack/bootstrap"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s"],"mappings":"sCACE,IAAIA,EAAmB,GAGvB,SAASC,EAAoBC,GAG5B,GAAGF,EAAiBE,GACnB,OAAOF,EAAiBE,GAAUC,QAGnC,IAAIC,EAASJ,EAAiBE,GAAY,CACzCG,EAAGH,EACHI,GAAG,EACHH,QAAS,IAUV,OANAI,EAAQL,GAAUM,KAAKJ,EAAOD,QAASC,EAAQA,EAAOD,QAASF,GAG/DG,EAAOE,GAAI,EAGJF,EAAOD,QA0Df,OArDAF,EAAoBQ,EAAIF,EAGxBN,EAAoBS,EAAIV,EAGxBC,EAAoBU,EAAI,SAASR,EAASS,EAAMC,GAC3CZ,EAAoBa,EAAEX,EAASS,IAClCG,OAAOC,eAAeb,EAASS,EAAM,CAAEK,YAAY,EAAMC,IAAKL,KAKhEZ,EAAoBkB,EAAI,SAAShB,GACX,oBAAXiB,QAA0BA,OAAOC,aAC1CN,OAAOC,eAAeb,EAASiB,OAAOC,YAAa,CAAEC,MAAO,WAE7DP,OAAOC,eAAeb,EAAS,aAAc,CAAEmB,OAAO,KAQvDrB,EAAoBsB,EAAI,SAASD,EAAOE,GAEvC,GADU,EAAPA,IAAUF,EAAQrB,EAAoBqB,IAC/B,EAAPE,EAAU,OAAOF,EACpB,GAAW,EAAPE,GAA8B,iBAAVF,GAAsBA,GAASA,EAAMG,WAAY,OAAOH,EAChF,IAAII,EAAKX,OAAOY,OAAO,MAGvB,GAFA1B,EAAoBkB,EAAEO,GACtBX,OAAOC,eAAeU,EAAI,UAAW,CAAET,YAAY,EAAMK,MAAOA,IACtD,EAAPE,GAA4B,iBAATF,EAAmB,IAAI,IAAIM,KAAON,EAAOrB,EAAoBU,EAAEe,EAAIE,EAAK,SAASA,GAAO,OAAON,EAAMM,IAAQC,KAAK,KAAMD,IAC9I,OAAOF,GAIRzB,EAAoB6B,EAAI,SAAS1B,GAChC,IAAIS,EAAST,GAAUA,EAAOqB,WAC7B,WAAwB,OAAOrB,EAAgB,SAC/C,WAA8B,OAAOA,GAEtC,OADAH,EAAoBU,EAAEE,EAAQ,IAAKA,GAC5BA,GAIRZ,EAAoBa,EAAI,SAASiB,EAAQC,GAAY,OAAOjB,OAAOkB,UAAUC,eAAe1B,KAAKuB,EAAQC,IAGzG/B,EAAoBkC,EAAI,IAIjBlC,EAAoBA,EAAoBmC,EAAI,I","file":"dark.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 71);\n"],"sourceRoot":""}
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
define((function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=70)}({70:function(e,t,n){}})}));
|
||||
//# sourceMappingURL=light.js.map
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"sources":["webpack:///webpack/bootstrap"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s"],"mappings":"sCACE,IAAIA,EAAmB,GAGvB,SAASC,EAAoBC,GAG5B,GAAGF,EAAiBE,GACnB,OAAOF,EAAiBE,GAAUC,QAGnC,IAAIC,EAASJ,EAAiBE,GAAY,CACzCG,EAAGH,EACHI,GAAG,EACHH,QAAS,IAUV,OANAI,EAAQL,GAAUM,KAAKJ,EAAOD,QAASC,EAAQA,EAAOD,QAASF,GAG/DG,EAAOE,GAAI,EAGJF,EAAOD,QA0Df,OArDAF,EAAoBQ,EAAIF,EAGxBN,EAAoBS,EAAIV,EAGxBC,EAAoBU,EAAI,SAASR,EAASS,EAAMC,GAC3CZ,EAAoBa,EAAEX,EAASS,IAClCG,OAAOC,eAAeb,EAASS,EAAM,CAAEK,YAAY,EAAMC,IAAKL,KAKhEZ,EAAoBkB,EAAI,SAAShB,GACX,oBAAXiB,QAA0BA,OAAOC,aAC1CN,OAAOC,eAAeb,EAASiB,OAAOC,YAAa,CAAEC,MAAO,WAE7DP,OAAOC,eAAeb,EAAS,aAAc,CAAEmB,OAAO,KAQvDrB,EAAoBsB,EAAI,SAASD,EAAOE,GAEvC,GADU,EAAPA,IAAUF,EAAQrB,EAAoBqB,IAC/B,EAAPE,EAAU,OAAOF,EACpB,GAAW,EAAPE,GAA8B,iBAAVF,GAAsBA,GAASA,EAAMG,WAAY,OAAOH,EAChF,IAAII,EAAKX,OAAOY,OAAO,MAGvB,GAFA1B,EAAoBkB,EAAEO,GACtBX,OAAOC,eAAeU,EAAI,UAAW,CAAET,YAAY,EAAMK,MAAOA,IACtD,EAAPE,GAA4B,iBAATF,EAAmB,IAAI,IAAIM,KAAON,EAAOrB,EAAoBU,EAAEe,EAAIE,EAAK,SAASA,GAAO,OAAON,EAAMM,IAAQC,KAAK,KAAMD,IAC9I,OAAOF,GAIRzB,EAAoB6B,EAAI,SAAS1B,GAChC,IAAIS,EAAST,GAAUA,EAAOqB,WAC7B,WAAwB,OAAOrB,EAAgB,SAC/C,WAA8B,OAAOA,GAEtC,OADAH,EAAoBU,EAAEE,EAAQ,IAAKA,GAC5BA,GAIRZ,EAAoBa,EAAI,SAASiB,EAAQC,GAAY,OAAOjB,OAAOkB,UAAUC,eAAe1B,KAAKuB,EAAQC,IAGzG/B,EAAoBkC,EAAI,IAIjBlC,EAAoBA,EAAoBmC,EAAI,I","file":"light.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 70);\n"],"sourceRoot":""}
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
/*! For license information please see module.js.LICENSE.txt */
|
||||
define(["react","@grafana/ui","react-dom","lodash","@grafana/runtime","@grafana/data"],(function(e,t,n,r,o,i){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=72)}([function(t,n){t.exports=e},function(e,t,n){e.exports=n(48)()},function(e,t){e.exports=function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t){e.exports=function(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t){function n(){return e.exports=n=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},e.exports.default=e.exports,e.exports.__esModule=!0,n.apply(this,arguments)}e.exports=n,e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t){e.exports=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var i=typeof r;if("string"===i||"number"===i)e.push(r);else if(Array.isArray(r)){if(r.length){var a=o.apply(null,r);a&&e.push(a)}}else if("object"===i)if(r.toString===Object.prototype.toString)for(var s in r)n.call(r,s)&&r[s]&&e.push(s);else e.push(r.toString())}}return e.join(" ")}e.exports?(o.default=o,e.exports=o):void 0===(r=function(){return o}.apply(t,[]))||(e.exports=r)}()},function(e,n){e.exports=t},function(e,t,n){var r=n(50);e.exports=function(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)},e.exports.default=e.exports,e.exports.__esModule=!0},,function(e,t){e.exports=n},function(e,t){e.exports=r},function(e,t){e.exports=o},function(e,t,n){"use strict";e.exports=function e(t,n){if(t===n)return!0;if(t&&n&&"object"==typeof t&&"object"==typeof n){if(t.constructor!==n.constructor)return!1;var r,o,i;if(Array.isArray(t)){if((r=t.length)!=n.length)return!1;for(o=r;0!=o--;)if(!e(t[o],n[o]))return!1;return!0}if(t.constructor===RegExp)return t.source===n.source&&t.flags===n.flags;if(t.valueOf!==Object.prototype.valueOf)return t.valueOf()===n.valueOf();if(t.toString!==Object.prototype.toString)return t.toString()===n.toString();if((r=(i=Object.keys(t)).length)!==Object.keys(n).length)return!1;for(o=r;0!=o--;)if(!Object.prototype.hasOwnProperty.call(n,i[o]))return!1;for(o=r;0!=o--;){var a=i[o];if(!e(t[a],n[a]))return!1}return!0}return t!=t&&n!=n}},function(e,t,n){"use strict";e.exports=function(e,t,n,r,o,i,a,s){if(!e){var l;if(void 0===t)l=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var u=[n,r,o,i,a,s],c=0;(l=new Error(t.replace(/%s/g,(function(){return u[c++]})))).name="Invariant Violation"}throw l.framesToPop=1,l}}},function(e,t,n){"use strict";var r=n(26),o="function"==typeof Symbol&&"symbol"==typeof Symbol("foo"),i=Object.prototype.toString,a=Array.prototype.concat,s=Object.defineProperty,l=s&&function(){var e={};try{for(var t in s(e,"x",{enumerable:!1,value:e}),e)return!1;return e.x===e}catch(e){return!1}}(),u=function(e,t,n,r){var o;(!(t in e)||"function"==typeof(o=r)&&"[object Function]"===i.call(o)&&r())&&(l?s(e,t,{configurable:!0,enumerable:!1,value:n,writable:!0}):e[t]=n)},c=function(e,t){var n=arguments.length>2?arguments[2]:{},i=r(t);o&&(i=a.call(i,Object.getOwnPropertySymbols(t)));for(var s=0;s<i.length;s+=1)u(e,i[s],t[i[s]],n[i[s]])};c.supportsDescriptors=!!l,e.exports=c},function(e,t,n){"use strict";var r=function(){};e.exports=r},function(e,t,n){"use strict";function r(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}n.d(t,"a",(function(){return r}))},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeoLine truncated
|
||||
//# sourceMappingURL=module.js.map
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
/*!
|
||||
Copyright (c) 2018 Jed Watson.
|
||||
Licensed under the MIT License (MIT), see
|
||||
http://jedwatson.github.io/classnames
|
||||
*/
|
||||
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */
|
||||
|
||||
/**
|
||||
* A better abstraction over CSS.
|
||||
*
|
||||
* @copyright Oleg Isonen (Slobodskoi) / Isonen 2014-present
|
||||
* @website https://github.com/cssinjs/jss
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/** @license React v16.13.1
|
||||
* react-is.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**!
|
||||
* @fileOverview Kickass library to create and place poppers near their reference elements.
|
||||
* @version 1.16.1
|
||||
* @license
|
||||
* Copyright (c) 2016 Federico Zivolo and contributors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**!
|
||||
* @fileOverview Kickass library to create and place poppers near their reference elements.
|
||||
* @version 1.16.1-lts
|
||||
* @license
|
||||
* Copyright (c) 2016 Federico Zivolo and contributors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
-1
@@ -1 +0,0 @@
|
||||
{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///external \"react\"","webpack:///../node_modules/prop-types/index.js","webpack:///../node_modules/@babel/runtime/helpers/assertThisInitialized.js","webpack:///../node_modules/@babel/runtime/helpers/defineProperty.js","webpack:///../node_modules/@babel/runtime/helpers/extends.js","webpack:///../node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js","webpack:///../node_modules/classnames/index.js","webpack:///external \"@grafana/ui\"","webpack:///../node_modules/@babel/runtime/helpers/inheritsLoose.js","webpack:///external \"react-dom\"","webpack:///external \"lodash\"","webpack:///external \"@grafana/runtime\"","webpack:///../node_modules/fast-deep-equal/index.js","webpack:///../node_modules/invariant/browser.js","webpack:///../node_modules/define-properties/index.js","webpack:///../node_modules/warning/warning.js","webpack:///../node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js","webpack:///../node_modules/webpack/buildin/global.js","webpack:///../node_modules/@babel/runtime/helpers/esm/unsupportedIterableToArray.js","webpack:///../node_modules/function-bind/index.js","webpack:///../node_modules/call-bind/index.js","webpack:///../node_modules/popper.js/dist/esm/popper.js","webpack:///../node_modules/@hypnosphi/create-react-context/lib/index.js","webpack:///../node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js","webpack:///../node_modules/object-keys/index.js","webpack:///../node_modules/object-keys/isArguments.js","webpack:///../node_modules/call-bind/callBound.js","webpack:///../node_modules/get-intrinsic/index.js","webpack:///../node_modules/has-symbols/shams.js","webpack:///../node_modules/object-is/implementation.js","webpack:///../node_modules/object-is/polyfill.js","webpack:///../node_modules/regexp.prototype.flags/implementation.js","webpack:///../node_modules/regexp.prototype.flags/polyfill.js","webpack:///../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js","webpack:///../node_modules/css-loader/dist/runtime/api.js","webpack:///external \"@grafana/data\"","webpack:///../node_modules/dayjs/dayjs.min.js","webpack:///../node_modules/lodash.debounce/index.js","webpack:///../node_modules/deep-equal/index.js","webpack:///../node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js","webpack:///../node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js","webpack:///../node_modules/@babel/runtime/helpers/esm/iterableToArray.js","webpack:///../node_modules/@babel/runtime/helpers/esm/arrayWithHoles.js","webpack:///../node_modules/@babel/runtime/helpers/esm/nonIterableRest.js","webpack:///../node_modules/@material-ui/core/node_modules/popper.js/dist/esm/popper.js","webpack:///../node_modules/prop-types/factoryWithThrowingShims.js","webpack:///../node_modules/prop-types/lib/ReactPropTypesSecret.js","webpack:///../node_modules/@babel/runtime/helpers/setPrototypeOf.js","webpack:///../node_modules/object-keys/implementation.js","webpack:///../node_modules/is-arguments/index.js","webpack:///../node_modules/has-symbols/index.js","webpack:///../node_modules/function-bind/implementation.js","webpack:///../node_modules/has/src/index.js","webpack:///../node_modules/object-is/index.js","webpack:///../node_modules/object-is/shim.js","webpack:///../node_modules/is-regex/index.js","webpack:///../node_modules/regexp.prototype.flags/index.js","webpack:///../node_modules/regexp.prototype.flags/shim.js","webpack:///../node_modules/is-date-object/index.js","webpack:///../node_modules/@hypnosphi/create-react-context/lib/implementation.js","webpack:///../node_modules/gud/index.js","webpack:///../node_modules/react-is/index.js","webpack:///../node_modules/react-is/cjs/react-is.production.min.js","webpack:///./static/css/timely-bootstrap.css?617f","webpack:///./static/css/timely-bootstrap.css","webpack:///./static/css/timely.css?f98e","webpack:///./static/css/timely.css","webpack:///../node_modules/tslib/tslib.es6.js","webpack:///../node_modules/rxjs/dist/esm5/internal/util/isFunction.js","webpack:///../node_modules/rxjs/dist/esm5/internal/util/lift.js","webpack:///../node_modules/rxjs/node_modules/tslib/tslib.es6.js","webpack:///../node_modules/rxjs/dist/esm5/internal/util/UnsubscriptionError.js","webpack:///../node_modules/rxjs/dist/esm5/internal/util/createErrorClass.js","webpack:///../node_modules/rxjs/dist/esm5/internal/util/arrRemove.js","webpack:///../node_modules/rxjs/dist/esm5/internal/Subscription.js","webpack:///../node_modules/rxjs/dist/esm5/internal/config.js","webpack:///../node_modules/rxjs/dist/esm5/internal/scheduler/timeoutProvider.js","webpack:///../node_modules/rxjs/dist/esm5/internal/util/reportUnhandledError.js","webpack:///../node_modules/rxjs/dist/esm5/internal/util/noop.js","webpack:///../node_modules/rxjs/dist/esm5/internal/NotificationFactories.js","webpack:///../node_modules/rxjs/dist/esm5/internal/util/errorContext.js","webpack:///../node_modules/rxjs/dist/esm5/inteLine truncated
|
||||
Vendored
-40
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"type": "datasource",
|
||||
"name": "Timely",
|
||||
"id": "nsa-timely-datasource",
|
||||
"category": "tsdb",
|
||||
"metrics": true,
|
||||
"backend": true,
|
||||
"alerting": true,
|
||||
"executable": "timely_datasource_backend",
|
||||
"info": {
|
||||
"description": "Open source time series database backed by Accumulo",
|
||||
"author": {
|
||||
"name": "National Security Agency"
|
||||
},
|
||||
"keywords": ["Simple"],
|
||||
"logos": {
|
||||
"small": "static/img/timely_square_small.png",
|
||||
"large": "static/img/timely_square_large.png"
|
||||
},
|
||||
"links": [
|
||||
{
|
||||
"name": "Website",
|
||||
"url": "https://code.nsa.gov/timely"
|
||||
},
|
||||
{
|
||||
"name": "License",
|
||||
"url": "https://github.com/NationalSecurityAgency/timely/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"screenshots": [],
|
||||
"version": "2.1.4-SNAPSHOT",
|
||||
"updated": "2024-03-13"
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "2.2.6",
|
||||
"slate-plain-serializer": "0.7.10",
|
||||
"grafanaVersion": "6.5.x",
|
||||
"plugins": []
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
$box-shadow-dimensions: 0 0 0 0.2rem;
|
||||
$placeholder-color: #6c757d;
|
||||
|
||||
.rbt {
|
||||
&-input-multi {
|
||||
// Bootstrap 4 focus style
|
||||
&.focus {
|
||||
background-color: #fff;
|
||||
border-color: #80bdff;
|
||||
box-shadow: $box-shadow-dimensions rgba(0, 123, 255, 0.25);
|
||||
color: #495057;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&.is-invalid.focus {
|
||||
border-color: #dc3545;
|
||||
box-shadow: $box-shadow-dimensions rgba(220, 53, 69, 0.25);
|
||||
}
|
||||
|
||||
&.is-valid.focus {
|
||||
border-color: #28a745;
|
||||
box-shadow: $box-shadow-dimensions rgba(40, 167, 69, 0.25);
|
||||
}
|
||||
|
||||
input {
|
||||
// Firefox
|
||||
&::-moz-placeholder {
|
||||
color: $placeholder-color;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
// Internet Explorer 10+
|
||||
&:-ms-input-placeholder {
|
||||
color: $placeholder-color;
|
||||
}
|
||||
|
||||
// Safari and Chrome
|
||||
&::-webkit-input-placeholder {
|
||||
color: $placeholder-color;
|
||||
}
|
||||
}
|
||||
|
||||
// Override height in main CSS file :/
|
||||
& .rbt-input-main,
|
||||
&.form-control-lg .rbt-input-main,
|
||||
&.form-control-sm .rbt-input-main {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&-token {
|
||||
margin: 1px 3px 2px 0;
|
||||
}
|
||||
}
|
||||
-201
@@ -1,201 +0,0 @@
|
||||
.rbt .rbt-input-main::-ms-clear {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu
|
||||
*/
|
||||
.rbt-menu {
|
||||
margin-bottom: 2px !important;
|
||||
}
|
||||
|
||||
.rbt-menu > .dropdown-item {
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis !important;
|
||||
}
|
||||
|
||||
.rbt-menu > .dropdown-item:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.rbt-menu-pagination-option {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multi-select Input
|
||||
*/
|
||||
.rbt-input-multi {
|
||||
cursor: text !important;
|
||||
overflow: hidden !important;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.rbt-input-multi.focus {
|
||||
border-color: #80bdff !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25) !important;
|
||||
color: #495057 !important;
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
.rbt-input-multi.form-control {
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.rbt-input-multi.form-control[disabled] {
|
||||
background-color: #e9ecef !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.rbt-input-multi.is-invalid.focus {
|
||||
border-color: #dc3545 !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25) !important;
|
||||
}
|
||||
|
||||
.rbt-input-multi.is-valid.focus {
|
||||
border-color: #28a745 !important;
|
||||
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25) !important;
|
||||
}
|
||||
|
||||
.rbt-input-multi input::-moz-placeholder {
|
||||
color: #6c757d !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.rbt-input-multi input:-ms-input-placeholder {
|
||||
color: #6c757d !important;
|
||||
}
|
||||
|
||||
.rbt-input-multi input::-webkit-input-placeholder {
|
||||
color: #6c757d !important;
|
||||
}
|
||||
|
||||
.rbt-input-multi .rbt-input-wrapper {
|
||||
align-items: flex-start !important;
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
margin-bottom: -4px !important;
|
||||
margin-top: -1px !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.rbt-input-multi .rbt-input-main {
|
||||
margin: 1px 0 4px !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close Button
|
||||
*/
|
||||
.rbt-close {
|
||||
z-index: 1 !important;
|
||||
}
|
||||
|
||||
.rbt-close-lg {
|
||||
font-size: 24px !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Token
|
||||
*/
|
||||
.rbt-token {
|
||||
background-color: #e7f4ff !important;
|
||||
border: 0 !important;
|
||||
border-radius: 0.25rem !important;
|
||||
color: #007bff !important;
|
||||
display: inline-block !important;
|
||||
line-height: 1em !important;
|
||||
margin: 1px 3px 2px 0 !important;
|
||||
padding: 4px 7px !important;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.rbt-token-disabled {
|
||||
background-color: rgba(0, 0, 0, 0.1) !important;
|
||||
color: #495057 !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
.rbt-token-removeable {
|
||||
cursor: pointer !important;
|
||||
padding-right: 21px !important;
|
||||
}
|
||||
|
||||
.rbt-token-active {
|
||||
background-color: #007bff !important;
|
||||
color: #fff !important;
|
||||
outline: none !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.rbt-token .rbt-token-remove-button {
|
||||
bottom: 0 !important;
|
||||
color: inherit !important;
|
||||
font-size: inherit !important;
|
||||
font-weight: normal !important;
|
||||
opacity: 1 !important;
|
||||
outline: none !important;
|
||||
padding: 3px 7px !important;
|
||||
position: absolute !important;
|
||||
right: 0 !important;
|
||||
text-shadow: none !important;
|
||||
top: -2px !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loader + CloseButton container
|
||||
*/
|
||||
.rbt-aux {
|
||||
align-items: center !important;
|
||||
display: flex !important;
|
||||
bottom: 0 !important;
|
||||
justify-content: center !important;
|
||||
pointer-events: none !important;
|
||||
/* Don't block clicks on the input */
|
||||
position: absolute !important;
|
||||
right: 0 !important;
|
||||
top: 0 !important;
|
||||
width: 34px !important;
|
||||
}
|
||||
|
||||
.rbt-aux-lg {
|
||||
width: 46px !important;
|
||||
}
|
||||
|
||||
.rbt-aux .rbt-close {
|
||||
margin-top: -4px !important;
|
||||
pointer-events: auto !important;
|
||||
/* Override pointer-events: none; above */
|
||||
}
|
||||
|
||||
.has-aux .rbt-input {
|
||||
padding-right: 34px !important;
|
||||
}
|
||||
|
||||
.rbt-highlight-text {
|
||||
background-color: inherit !important;
|
||||
color: inherit !important;
|
||||
font-weight: bold !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Input Groups
|
||||
*/
|
||||
.input-group > .rbt {
|
||||
flex: 1 !important;
|
||||
}
|
||||
|
||||
.input-group > .rbt .rbt-input-hint,
|
||||
.input-group > .rbt .rbt-aux {
|
||||
z-index: 5 !important;
|
||||
}
|
||||
|
||||
.input-group > .rbt:not(:first-child) .form-control {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
}
|
||||
|
||||
.input-group > .rbt:not(:last-child) .form-control {
|
||||
border-top-right-radius: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
$animation: loader-animation 600ms infinite linear;
|
||||
$inset: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
$placeholder-color: #999;
|
||||
|
||||
.rbt {
|
||||
&-menu {
|
||||
margin-bottom: 2px; // Spacing for dropup
|
||||
|
||||
& > li a {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-pagination-option {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide IE's native "clear" button
|
||||
& .rbt-input-main::-ms-clear {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-input-multi {
|
||||
cursor: text;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: auto;
|
||||
|
||||
// Apply Bootstrap focus styles
|
||||
&.focus {
|
||||
box-shadow: $inset, 0 0 8px rgba(102, 175, 233, 0.6);
|
||||
border-color: #66afe9;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
// BS4 uses the :disabled pseudo-class, which doesn't work with non-inputs.
|
||||
&.form-control[disabled] {
|
||||
background-color: #e9ecef;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
// Apply Bootstrap placeholder styles
|
||||
input {
|
||||
// Firefox
|
||||
&::-moz-placeholder {
|
||||
color: $placeholder-color;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
// Internet Explorer 10+
|
||||
&:-ms-input-placeholder {
|
||||
color: $placeholder-color;
|
||||
}
|
||||
|
||||
// Safari and Chrome
|
||||
&::-webkit-input-placeholder {
|
||||
color: $placeholder-color;
|
||||
}
|
||||
}
|
||||
|
||||
.rbt-input-wrapper {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: -4px;
|
||||
margin-top: -1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.rbt-input-main {
|
||||
// Set input height for cross-browser consistency
|
||||
height: 20px;
|
||||
margin: 1px 0 4px;
|
||||
}
|
||||
|
||||
&.input,
|
||||
&.form-control {
|
||||
&-lg {
|
||||
.rbt-input-main {
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
&-sm {
|
||||
.rbt-input-main {
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-close {
|
||||
z-index: 1;
|
||||
|
||||
&-lg {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
&-token {
|
||||
background-color: #e7f4ff;
|
||||
border: 0;
|
||||
border-radius: 2px;
|
||||
color: #1f8dd6;
|
||||
display: inline-block;
|
||||
line-height: 1em;
|
||||
margin: 0 3px 3px 0;
|
||||
padding: 4px 7px;
|
||||
position: relative;
|
||||
|
||||
&-disabled {
|
||||
background-color: #ddd;
|
||||
color: #888;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&-removeable {
|
||||
cursor: pointer;
|
||||
padding-right: 21px;
|
||||
}
|
||||
|
||||
&-active {
|
||||
background-color: #1f8dd6;
|
||||
color: #fff;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
& &-remove-button {
|
||||
bottom: 0;
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
font-weight: normal;
|
||||
opacity: 1;
|
||||
outline: none;
|
||||
padding: 3px 7px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
text-shadow: none;
|
||||
top: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
&-loader {
|
||||
-moz-animation: $animation;
|
||||
-webkit-animation: $animation;
|
||||
animation: $animation;
|
||||
border: 1px solid #d5d5d5;
|
||||
border-radius: 50%;
|
||||
border-top-color: #1f8dd6;
|
||||
display: block;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
|
||||
&-lg {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&-aux {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
bottom: 0;
|
||||
justify-content: center;
|
||||
pointer-events: none; /* Don't block clicks on the input */
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 34px;
|
||||
|
||||
&-lg {
|
||||
width: 46px;
|
||||
}
|
||||
|
||||
& .rbt-close {
|
||||
margin-top: -4px;
|
||||
pointer-events: auto; /* Override pointer-events: none; above */
|
||||
}
|
||||
}
|
||||
|
||||
.has-aux &-input {
|
||||
padding-right: 34px;
|
||||
}
|
||||
|
||||
&-highlight-text {
|
||||
background-color: inherit;
|
||||
color: inherit;
|
||||
font-weight: bold;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Input Groups */
|
||||
.input-group > .rbt {
|
||||
flex: 1;
|
||||
|
||||
// Form-controls within input-groups have a higher z-index.
|
||||
& .rbt-input-hint,
|
||||
& .rbt-aux {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
&:not(:first-child) .form-control {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
&:not(:last-child) .form-control {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Validation States */
|
||||
.has-error .rbt-input-multi.focus {
|
||||
border-color: #843534;
|
||||
box-shadow: $inset, 0 0 6px #ce8483;
|
||||
}
|
||||
|
||||
.has-warning .rbt-input-multi.focus {
|
||||
border-color: #66512c;
|
||||
box-shadow: $inset, 0 0 6px #c0a16b;
|
||||
}
|
||||
|
||||
.has-success .rbt-input-multi.focus {
|
||||
border-color: #2b542c;
|
||||
box-shadow: $inset, 0 0 6px #67b168;
|
||||
}
|
||||
|
||||
@keyframes loader-animation {
|
||||
to {
|
||||
transform: rotate(1turn);
|
||||
}
|
||||
}
|
||||
-10602
File diff suppressed because it is too large.
Load diff
-20322
File diff suppressed because it is too large.
Load diff
-20321
File diff suppressed because it is too large.
Load diff
-1
@@ -1 +0,0 @@
|
||||
div.timely .dropdown-item,div.timely .dropdown-item-text,div.timely input.form-control{color:#c7d0d9;background-color:#0b0c0e}.dropdown-item:active,.dropdown-item:focus,div.timely .dropdown-item.active,div.timely .dropdown-item:hover{background-color:#4f5255}.dropdown-item:disabled,div.timely .dropdown-header,div.timely .dropdown-item.disabled{color:#0b0c0e}div.timely .dropdown-menu{background-color:#0b0c0e;box-shadow:0 2px 2px 2px #31343b}div.timely input.form-control:focus{color:#c7d0d9;outline:0;box-shadow:0 0 0 2px #141619,0 0 0 4px #1f60c4;outline-offset:2px;transition:all .2s cubic-bezier(.19,1,.22,1) 0s}div.timely mark.rbt-highlight-text{background:linear-gradient(90deg,#56585c,#4c5057);color:#ff0}
|
||||
-1
@@ -1 +0,0 @@
|
||||
div.timely input.form-control{color:#464c54;background-color:#fff}div.timely .dropdown-item,div.timely .dropdown-item-text{color:#464c54}.dropdown-item:active,.dropdown-item:focus,div.timely .dropdown-item.active,div.timely .dropdown-item:hover{color:#464c54;background-color:#e3e6e9}.dropdown-item:disabled,div.timely .dropdown-item.disabled{color:#abadaf}div.timely .dropdown-header{color:#464c54}div.timely .dropdown-menu{box-shadow:0 4px 2px 0 #cbcbcb}div.timely input.form-control:focus{color:#464c54;outline:0;box-shadow:0 0 0 2px #fff,0 0 0 4px #5794f2;outline-offset:2px;transition:all .2s cubic-bezier(.19,1,.22,1) 0s}div.timely mark.rbt-highlight-text{background:linear-gradient(90deg,#bfc0c1,#abadaf);color:#ff0}
|
||||
@@ -1,96 +0,0 @@
|
||||
module github.com/NationalSecurityAgency/timely-datasource
|
||||
|
||||
go 1.21
|
||||
|
||||
toolchain go1.22.1
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.218.0
|
||||
github.com/hashicorp/go-hclog v1.6.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
github.com/apache/arrow/go/v15 v15.0.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
github.com/chromedp/cdproto v0.0.0-20220208224320-6efb837e6bc2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/elazarl/goproxy v0.0.0-20230731152917-f99041a5c027 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/getkin/kin-openapi v0.120.0 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/flatbuffers v23.5.26+incompatible // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
|
||||
github.com/hashicorp/go-plugin v1.6.0 // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/invopop/yaml v0.2.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.16.7 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/magefile/mage v1.15.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattetti/filebuffer v1.0.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/oklog/run v1.1.0 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.18 // indirect
|
||||
github.com/prometheus/client_golang v1.18.0 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.46.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect
|
||||
github.com/unknwon/com v1.0.1 // indirect
|
||||
github.com/unknwon/log v0.0.0-20150304194804-e617c87089d3 // indirect
|
||||
github.com/urfave/cli v1.22.14 // indirect
|
||||
github.com/zeebo/xxh3 v1.0.2 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.49.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.22.0 // indirect
|
||||
go.opentelemetry.io/contrib/samplers/jaegerremote v0.18.0 // indirect
|
||||
go.opentelemetry.io/otel v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.1.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
||||
golang.org/x/mod v0.13.0 // indirect
|
||||
golang.org/x/net v0.22.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.14.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -1,367 +0,0 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/apache/arrow/go/v15 v15.0.0 h1:1zZACWf85oEZY5/kd9dsQS7i+2G5zVQcbKTHgslqHNA=
|
||||
github.com/apache/arrow/go/v15 v15.0.0/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
|
||||
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/chromedp/cdproto v0.0.0-20220208224320-6efb837e6bc2 h1:XCdvHbz3LhewBHN7+mQPx0sg/Hxil/1USnBmxkjHcmY=
|
||||
github.com/chromedp/cdproto v0.0.0-20220208224320-6efb837e6bc2/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/elazarl/goproxy v0.0.0-20230731152917-f99041a5c027 h1:1L0aalTpPz7YlMxETKpmQoWMBkeiuorElZIXoNmgiPE=
|
||||
github.com/elazarl/goproxy v0.0.0-20230731152917-f99041a5c027/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac h1:9yrT5tmn9Zc0ytWPASlaPwQfQMQYnRf0RSDe1XvHw0Q=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/getkin/kin-openapi v0.120.0 h1:MqJcNJFrMDFNc07iwE8iFC5eT2k/NPUFDIpNeiZv8Jg=
|
||||
github.com/getkin/kin-openapi v0.120.0/go.mod h1:PCWw/lfBrJY4HcdqE3jj+QFkaFK8ABoqo7PvqVhXXqw=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg=
|
||||
github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.218.0 h1:hKu6ziTgHHfdc/7UpIcWtBoP44/a7VkAJIBnECoRqTg=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.218.0/go.mod h1:Cu+ezYbFY+IYDhIbPhkYegE3wl9VKrntSBkuVuJr+ZE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
|
||||
github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I=
|
||||
github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A=
|
||||
github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI=
|
||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
|
||||
github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
|
||||
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
|
||||
github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
|
||||
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM=
|
||||
github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
|
||||
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
|
||||
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
|
||||
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
|
||||
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
|
||||
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y=
|
||||
github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY=
|
||||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 h1:aVGB3YnaS/JNfOW3tiHIlmNmTDg618va+eT0mVomgyI=
|
||||
github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8/go.mod h1:fVle4kNr08ydeohzYafr20oZzbAkhQT39gKK/pFQ5M4=
|
||||
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
|
||||
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
|
||||
github.com/unknwon/log v0.0.0-20150304194804-e617c87089d3 h1:4EYQaWAatQokdji3zqZloVIW/Ke1RQjYw2zHULyrHJg=
|
||||
github.com/unknwon/log v0.0.0-20150304194804-e617c87089d3/go.mod h1:1xEUf2abjfP92w2GZTV+GgaRxXErwRXcClbUwrNJffU=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk=
|
||||
github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
||||
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
|
||||
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.49.0 h1:RtcvQ4iw3w9NBB5yRwgA4sSa82rfId7n4atVpvKx3bY=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.49.0/go.mod h1:f/PbKbRd4cdUICWell6DmzvVJ7QrmBgFrRHjXmAXbK4=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.22.0 h1:bAHX+zN/inu+Rbqk51REmC8oXLl+Dw6pp9ldQf/onaY=
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.22.0/go.mod h1:bH9GkgkN21mscXcQP6lQJYI8XnEPDxlTN/ZOBuHDjqE=
|
||||
go.opentelemetry.io/contrib/samplers/jaegerremote v0.18.0 h1:Q9PrD94WoMolBx44ef5UWWvufpVSME0MiSymXZfedso=
|
||||
go.opentelemetry.io/contrib/samplers/jaegerremote v0.18.0/go.mod h1:tjp49JHNvreAAoWjdCHIVD7NXMjuJ3Dp/9iNOuPPlC8=
|
||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM=
|
||||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
|
||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
||||
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
|
||||
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
|
||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
|
||||
go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191020152052-9984515f0562/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
gonum.org/v1/gonum v0.12.0 h1:xKuo6hzt+gMav00meVPUlXwSdoEJP46BR+wdxQEFK2o=
|
||||
gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
|
||||
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
|
||||
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo=
|
||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -1,8 +0,0 @@
|
||||
// This file is needed because it is used by vscode and other tools that
|
||||
// call `jest` directly. However, unless you are doing anything special
|
||||
// do not edit this file
|
||||
|
||||
const standard = require('@grafana/toolkit/src/config/jest.plugin.config');
|
||||
|
||||
// This process will use the same config that `yarn test` is using
|
||||
module.exports = standard.jestConfig();
|
||||
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"name": "timely-datasource",
|
||||
"version": "2.1.4-SNAPSHOT",
|
||||
"description": "Timely",
|
||||
"backend": true,
|
||||
"alerting": true,
|
||||
"executable": "timely_datasource_backend",
|
||||
"scripts": {
|
||||
"build": "grafana-toolkit plugin:build",
|
||||
"test": "grafana-toolkit plugin:test",
|
||||
"dev": "grafana-toolkit plugin:dev",
|
||||
"watch": "grafana-toolkit plugin:dev --watch"
|
||||
},
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@grafana/toolkit": "^8.4.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12 <17"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grafana/data": "^8.4.5",
|
||||
"@grafana/runtime": "^8.4.5",
|
||||
"@grafana/slate-react": "0.22.10-grafana",
|
||||
"@grafana/ui": "^8.4.5",
|
||||
"@material-ui/core": "^4.12.3",
|
||||
"@types/classnames": "2.3.1",
|
||||
"@types/lodash": "4.14.176",
|
||||
"@types/react-bootstrap-typeahead": "5.1.8",
|
||||
"@types/slate-plain-serializer": "0.7.1",
|
||||
"@types/slate-react": "0.50.1",
|
||||
"classnames": "2.3.1",
|
||||
"dayjs": "1.10.7",
|
||||
"react-bootstrap-typeahead": "5.1.1",
|
||||
"rxjs": "7.3.0",
|
||||
"slate-plain-serializer": "0.7.13",
|
||||
"tmpl": "1.0.5",
|
||||
"tslib": "^2.3.1",
|
||||
"ws": "5.2.3"
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package main
|
||||
|
||||
type TimelyQueryForm struct {
|
||||
Metric string `json:"metric"`
|
||||
Alias string `json:"alias"`
|
||||
Aggregator string `json:"aggregator"`
|
||||
DisableDownsampling bool `json:"disableDownsampling"`
|
||||
DownsampleAggregator string `json:"downsampleAggregator"`
|
||||
DownsampleFillPolicy string `json:"downsampleFillPolicy"`
|
||||
DownsampleInterval string `json:"downsampleInterval"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Filters []Filter `json:"filters"`
|
||||
ShouldComputeRate bool `json:"shouldComputeRate"`
|
||||
RateInterval string `json:"rateInterval"`
|
||||
IsCounter bool `json:"isCounter"`
|
||||
CounterMax string `json:"counterMax"`
|
||||
CounterResetValue string `json:"counterResetValue"`
|
||||
Tsuids []string `json:"tsuids"`
|
||||
QueryType string `json:"queryType"`
|
||||
RefId string `json:"refId"`
|
||||
Datasource string `json:"datasource"`
|
||||
DatasourceId int64 `json:"datasourceId"`
|
||||
IntervalMs int64 `json:"intervalMs"`
|
||||
MaxDataPoints int64 `json:"maxDataPoints"`
|
||||
OrgId int64 `json:"ordId"`
|
||||
}
|
||||
|
||||
type TimelyQueryServer struct {
|
||||
Metric string `json:"metric"`
|
||||
Aggregator string `json:"aggregator"`
|
||||
DisableDownsampling bool `json:"disableDownsampling"`
|
||||
DownsampleAggregator string `json:"downsampleAggregator"`
|
||||
DownsampleFillPolicy string `json:"downsampleFillPolicy"`
|
||||
DownsampleInterval string `json:"downsampleInterval"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Filters []Filter `json:"filters"`
|
||||
ShouldComputeRate bool `json:"shouldComputeRate"`
|
||||
RateInterval string `json:"rateInterval"`
|
||||
IsCounter bool `json:"isCounter"`
|
||||
CounterMax string `json:"counterMax"`
|
||||
CounterResetValue string `json:"counterResetValue"`
|
||||
Tsuids []string `json:"tsuids"`
|
||||
QueryType string `json:"queryType"`
|
||||
RefId string `json:"refId"`
|
||||
}
|
||||
|
||||
type Filter struct {
|
||||
Type string `json:"type"`
|
||||
TagK string `json:"tagk"`
|
||||
Filter string `json:"filter"`
|
||||
GroupBy bool `json:"groupBy"`
|
||||
}
|
||||
|
||||
type RateOptions struct {
|
||||
Interval int32 `json:"interval"`
|
||||
Counter bool `json:"counter"`
|
||||
CounterMax int32 `json:"counterMax"`
|
||||
ResetValue int32 `json:"resetValue"`
|
||||
}
|
||||
|
||||
type TimelyQuery struct {
|
||||
Metric string `json:"metric"`
|
||||
Aggregator string `json:"aggregator"`
|
||||
Rate bool `json:"rate"`
|
||||
RateOptions RateOptions `json:"rateOptions"`
|
||||
Downsample string `json:"downsample"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
Filters []Filter `json:"filters"`
|
||||
Tsuids []string `json:"tsuids"`
|
||||
}
|
||||
|
||||
type TimelyRequest struct {
|
||||
MsResolution bool `json:"msResolution"`
|
||||
GlobalAnnotations bool `json:"globalAnnotations"`
|
||||
Start int64 `json:"start"`
|
||||
End int64 `json:"end"`
|
||||
Queries []TimelyQuery `json:"queries"`
|
||||
}
|
||||
|
||||
type TimelyResponse struct {
|
||||
Metric string `json:"metric"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
AggregatedTags []string `json:"aggregatedTags"`
|
||||
DataPoints map[int64]float64 `json:"dps"`
|
||||
}
|
||||
|
||||
type TimelyDataSourceOptions struct {
|
||||
TimelyHost string `json:"timelyHost"`
|
||||
HttpsPort string `json:"httpsPort"`
|
||||
OauthPassThru bool `json:"oauthPassThru"`
|
||||
UseClientCertWhenOAuthMissing bool `json:"useClientCertWhenOAuthMissing"`
|
||||
ClientCertificatePath string `json:"clientCertificatePath"`
|
||||
ClientKeyPath string `json:"clientKeyPath"`
|
||||
CertificateAuthorityPath string `json:"certificateAuthorityPath"`
|
||||
AllowInsecureSsl bool `json:"allowInsecureSsl"`
|
||||
}
|
||||
|
||||
type TimelyErrorResponse struct {
|
||||
ResponseCode int32 `json:responseCode`
|
||||
Message string `json:message`
|
||||
DetailMessage string `json:detailMessage`
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
|
||||
import { LegacyForms } from '@grafana/ui';
|
||||
import { TimelyDataSourceOptions } from './types';
|
||||
import * as React from 'react';
|
||||
|
||||
const { FormField, Switch } = LegacyForms;
|
||||
|
||||
interface Props extends DataSourcePluginOptionsEditorProps<TimelyDataSourceOptions> {}
|
||||
|
||||
interface State {}
|
||||
|
||||
export class ConfigEditor extends React.PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
onTimelyHostChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { onOptionsChange, options } = this.props;
|
||||
const jsonData = {
|
||||
...options.jsonData,
|
||||
timelyHost: event.target.value,
|
||||
};
|
||||
onOptionsChange({ ...options, jsonData });
|
||||
};
|
||||
|
||||
onHttpsPortChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { onOptionsChange, options } = this.props;
|
||||
const jsonData = {
|
||||
...options.jsonData,
|
||||
httpsPort: event.target.value,
|
||||
};
|
||||
onOptionsChange({ ...options, jsonData });
|
||||
};
|
||||
|
||||
onUseOAuthChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
|
||||
const { onOptionsChange, options } = this.props;
|
||||
const jsonData = {
|
||||
...options.jsonData,
|
||||
oauthPassThru: event.currentTarget.checked,
|
||||
};
|
||||
onOptionsChange({ ...options, jsonData });
|
||||
};
|
||||
|
||||
onUseClientCertWhenOAuthMissingChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
|
||||
const { onOptionsChange, options } = this.props;
|
||||
const jsonData = {
|
||||
...options.jsonData,
|
||||
useClientCertWhenOAuthMissing: event.currentTarget.checked,
|
||||
};
|
||||
onOptionsChange({ ...options, jsonData });
|
||||
};
|
||||
|
||||
onClientCertificatePathChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { onOptionsChange, options } = this.props;
|
||||
const jsonData = {
|
||||
...options.jsonData,
|
||||
clientCertificatePath: event.target.value,
|
||||
};
|
||||
onOptionsChange({ ...options, jsonData });
|
||||
};
|
||||
|
||||
onClientKeyPathChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { onOptionsChange, options } = this.props;
|
||||
const jsonData = {
|
||||
...options.jsonData,
|
||||
clientKeyPath: event.target.value,
|
||||
};
|
||||
onOptionsChange({ ...options, jsonData });
|
||||
};
|
||||
|
||||
onCertificateAuthorityPathChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { onOptionsChange, options } = this.props;
|
||||
const jsonData = {
|
||||
...options.jsonData,
|
||||
certificateAuthorityPath: event.target.value,
|
||||
};
|
||||
onOptionsChange({ ...options, jsonData });
|
||||
};
|
||||
|
||||
onAllowInsecureSslChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
|
||||
const { onOptionsChange, options } = this.props;
|
||||
const jsonData = {
|
||||
...options.jsonData,
|
||||
allowInsecureSsl: event.currentTarget.checked,
|
||||
};
|
||||
onOptionsChange({ ...options, jsonData });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { options } = this.props;
|
||||
const { jsonData } = options;
|
||||
|
||||
return (
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
label={'Hostname or IP'}
|
||||
labelWidth={10}
|
||||
inputWidth={20}
|
||||
disabled={false}
|
||||
onChange={this.onTimelyHostChange}
|
||||
tooltip={'Hostname or IP of Timely Server'}
|
||||
value={jsonData.timelyHost || ''}
|
||||
placeholder={'localhost'}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
label={'Https port'}
|
||||
labelWidth={10}
|
||||
inputWidth={20}
|
||||
onChange={this.onHttpsPortChange}
|
||||
value={jsonData.httpsPort || ''}
|
||||
placeholder={'4243'}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<Switch
|
||||
label={'Use OAuth token'}
|
||||
labelClass="width-10"
|
||||
tooltipPlacement={'top'}
|
||||
tooltip={'Send OAuth token if available'}
|
||||
checked={jsonData.oauthPassThru || false}
|
||||
onChange={this.onUseOAuthChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<Switch
|
||||
label={'Client cert for users'}
|
||||
labelClass="width-10"
|
||||
tooltipPlacement={'top'}
|
||||
tooltip={'If user is missing OAuth token, use client cert instead'}
|
||||
checked={jsonData.useClientCertWhenOAuthMissing || false}
|
||||
onChange={this.onUseClientCertWhenOAuthMissingChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
label={'Client cert path'}
|
||||
labelWidth={10}
|
||||
inputWidth={30}
|
||||
disabled={false}
|
||||
onChange={this.onClientCertificatePathChange}
|
||||
tooltip={'Full path to client certificate'}
|
||||
value={jsonData.clientCertificatePath || ''}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
label={'Client key path'}
|
||||
labelWidth={10}
|
||||
inputWidth={30}
|
||||
disabled={false}
|
||||
onChange={this.onClientKeyPathChange}
|
||||
tooltip={'Full path to client key'}
|
||||
value={jsonData.clientKeyPath || ''}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<FormField
|
||||
label={'CA path'}
|
||||
labelWidth={10}
|
||||
inputWidth={30}
|
||||
disabled={false}
|
||||
onChange={this.onCertificateAuthorityPathChange}
|
||||
tooltip={'Full path to certificate authority'}
|
||||
value={jsonData.certificateAuthorityPath || ''}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<Switch
|
||||
label={'Allow insecure ssl'}
|
||||
labelClass="width-10"
|
||||
tooltipPlacement={'top'}
|
||||
tooltip={'Allow ssl connection with unverified or self-signed certificates'}
|
||||
checked={jsonData.allowInsecureSsl || false}
|
||||
onChange={this.onAllowInsecureSslChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
Loaded 100 of 262 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user