Compare commits

..
Author SHA1 Message Date
Bill Oley 1597ec61ae scripts, interval, collectd, try to build grafana plugin 2024-03-28 16:42:59 -04:00
194 changed files with 159417 additions and 32067 deletions

No files matched your search

-1
View File
@@ -8,5 +8,4 @@ logs/
server/pki/
client/src/main/python/setup.py
grafana/timely-app/yarn-error.log
grafana/timely-app/data/
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>2.1.6-SNAPSHOT</version>
<version>2.1.4-SNAPSHOT</version>
</parent>
<artifactId>timely-analytics</artifactId>
<!--
+21 -17
View File
@@ -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,6 +19,7 @@ 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"
@@ -31,12 +32,18 @@ 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 ${NATIVE_DIR} ]]; then
mkdir -p "${NATIVE_DIR}"
if [[ -e ${TMP_DIR} ]]; then
rm -rf "${TMP_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"
@@ -46,15 +53,12 @@ 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
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}"
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}"
fi
echo "${JAVA_HOME}/bin/java ${JVM_ARGS} -jar ${BIN_DIR}/timely-balancer-*-exec.jar --instance=${INSTANCE}"
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>2.1.6-SNAPSHOT</version>
<version>2.1.4-SNAPSHOT</version>
</parent>
<artifactId>timely-balancer</artifactId>
<description>Timely Balancer</description>
@@ -91,21 +91,17 @@ 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) throws Exception {
HealthChecker healthChecker) {
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() {
@@ -920,8 +916,10 @@ public class MetricResolver {
protected void createAssignmentFile() {
try {
log.info("Creating assignment file: " + this.assignmentFile);
this.fs.create(this.assignmentFile);
log.info("Creating assignment file: " + balancerProperties.getAssignmentFile());
Path assignmentFile = new Path(balancerProperties.getAssignmentFile());
FileSystem fs = getFileSystem(assignmentFile);
fs.create(assignmentFile);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
@@ -929,7 +927,9 @@ public class MetricResolver {
protected long getLastWrittenToHdfsTimestamp() {
try {
FileStatus fileStatus = this.fs.getFileStatus(this.assignmentFile);
Path assignmentFile = new Path(balancerProperties.getAssignmentFile());
FileSystem fs = getFileSystem(assignmentFile);
FileStatus fileStatus = fs.getFileStatus(assignmentFile);
return fileStatus.getModificationTime();
} catch (FileNotFoundException e) {
createAssignmentFile();
@@ -960,15 +960,16 @@ 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();
FSDataInputStream iStream = this.fs.open(this.assignmentFile);
reader = new CsvReader(iStream, ',', Charset.forName("UTF-8"));
Path assignmentFile = new Path(balancerProperties.getAssignmentFile());
FileSystem fs = getFileSystem(assignmentFile);
FSDataInputStream iStream = fs.open(assignmentFile);
CsvReader reader = new CsvReader(iStream, ',', Charset.forName("UTF-8"));
reader.setUseTextQualifier(false);
// skip the headers
@@ -1030,9 +1031,6 @@ public class MetricResolver {
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
if (reader != null) {
reader.close();
}
balancerLock.writeLock().unlock();
try {
assignmentsIPRWLock.readLock().release();
@@ -1054,10 +1052,12 @@ public class MetricResolver {
nonCachedMetricsLocalLock.readLock().lock();
try {
if (!metricToHostMap.isEmpty()) {
if (!this.fs.exists(this.assignmentFile.getParent())) {
this.fs.mkdirs(this.assignmentFile.getParent());
Path assignmentFile = new Path(balancerProperties.getAssignmentFile());
FileSystem fs = getFileSystem(assignmentFile);
if (!fs.exists(assignmentFile.getParent())) {
fs.mkdirs(assignmentFile.getParent());
}
FSDataOutputStream oStream = this.fs.create(this.assignmentFile, true);
FSDataOutputStream oStream = fs.create(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.info("Wrote {} assignments to hdfs lastHdfsUpdate = lastLocalUpdate ({})", metricToHostMap.size(),
log.debug("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) throws Exception {
HealthChecker healthChecker) {
MetricResolver metricResolver = new MetricResolver(curatorFramework, balancerProperties, cacheProperties, healthChecker);
metricResolver.start();
return metricResolver;
@@ -48,7 +48,7 @@ public class TestBalancerConfiguration {
@Bean
public TestMetricResolver metricResolver(CuratorFramework curatorFramework, BalancerProperties balancerProperties, CacheProperties cacheProperties,
HealthChecker healthChecker) throws Exception {
HealthChecker healthChecker) {
TestMetricResolver metricResolver = new TestMetricResolver(curatorFramework, balancerProperties, cacheProperties, healthChecker);
metricResolver.start();
return metricResolver;
@@ -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) throws Exception {
HealthChecker healthChecker) {
super(curatorFramework, balancerProperties, cacheProperties, healthChecker);
}
+2 -2
View File
@@ -4,13 +4,13 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>2.1.6-SNAPSHOT</version>
<version>2.1.4-SNAPSHOT</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.6.dev0</python.client.version>
<python.client.version>2.1.4.dev0</python.client.version>
</properties>
<dependencies>
<dependency>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>2.1.6-SNAPSHOT</version>
<version>2.1.4-SNAPSHOT</version>
</parent>
<artifactId>collectd-nsq-plugin</artifactId>
<dependencies>
@@ -79,7 +79,6 @@ public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConf
} catch (IOException e1) {}
try {
clientPool.invalidateObject(client);
client = null;
} catch (Exception e2) {}
}
} finally {
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>2.1.6-SNAPSHOT</version>
<version>2.1.4-SNAPSHOT</version>
</parent>
<artifactId>collectd-plugin-parent</artifactId>
<dependencies>
@@ -3,7 +3,6 @@ package timely.collectd.plugin;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
@@ -26,9 +25,6 @@ public abstract class CollectDPluginParent {
private static final String GAUGE = "GAUGE";
private static final String DERIVE = "DERIVE";
private static final String ABSOLUTE = "ABSOLUTE";
private static final Collection<String> HADOOP_CONTEXTS = Arrays.asList("NameNode", "DataNode", "JobManager", "NodeManager", "JobHistoryServer",
"ResourceManager", "MRAppMaster");
private static final Pattern HADOOP_PATTERN_4_GROUPS = Pattern.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
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-_]+)");
@@ -68,8 +64,6 @@ public abstract class CollectDPluginParent {
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());
}
}
@@ -77,8 +71,8 @@ public abstract class CollectDPluginParent {
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]);
if (parts.length == 2 && !parts[0].isBlank() && !parts[1].isBlank()) {
m.put(parts[0].trim(), parts[1].trim());
}
}
}
@@ -105,10 +99,9 @@ public abstract class CollectDPluginParent {
} else {
addTag(tagMap, "host", host);
}
String[] hostSplit = host.split("\\.");
int nIdx = hostSplit[0].lastIndexOf('n');
int nIdx = host.indexOf('n');
if (-1 != nIdx) {
addTag(tagMap, "rack", hostSplit[0].substring(0, nIdx));
addTag(tagMap, "rack", host.substring(0, nIdx));
}
tagMap.putAll(addlTags);
@@ -119,53 +112,34 @@ public abstract class CollectDPluginParent {
switch (plugin) {
case STATSD_PREFIX:
Matcher hadoop_4_groups = HADOOP_PATTERN_4_GROUPS.matcher(typeInstance);
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 >= 4 && (HADOOP_CONTEXTS.contains(parts[0]) || hadoop_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 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);
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]);
}
}
}
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 (parts.length % 2 == 1) {
// 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
@@ -255,12 +229,6 @@ public abstract class CollectDPluginParent {
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
vl.setValues(Arrays.asList(vl.getValues().get(0)));
break;
case "GenericJMX":
metric.append("sys.").append(plugin).append(PERIOD).append(type).append(PERIOD).append(typeInstance);
String[] pluginInstanceSplit = pluginInstance.split("-");
@@ -270,7 +238,6 @@ public abstract class CollectDPluginParent {
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);
@@ -297,15 +264,9 @@ public abstract class CollectDPluginParent {
}
Double value = vl.getValues().get(i).doubleValue();
String tagString = tagMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining(" "));
if (metricName.isBlank() || timestamp == null || value == null) {
logDebug(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);
logDebug(String.format("Writing: %s", datapoint));
write(datapoint + "\n", out);
}
String datapoint = MessageFormat.format(PUT, metricName, timestamp.toString(), value.toString(), tagString);
logDebug(String.format("Writing: %s", datapoint));
write(datapoint + "\n", out);
}
}
@@ -356,4 +317,5 @@ public abstract class CollectDPluginParent {
private boolean notEmpty(String arg) {
return (null != arg) && !(arg.equals(""));
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>2.1.6-SNAPSHOT</version>
<version>2.1.4-SNAPSHOT</version>
</parent>
<artifactId>collectd-timely-plugin</artifactId>
<dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>2.1.6-SNAPSHOT</version>
<version>2.1.4-SNAPSHOT</version>
</parent>
<artifactId>timely-common</artifactId>
<dependencies>
@@ -32,7 +32,7 @@ public class QueryRequest extends AuthenticatedRequest implements HttpGetRequest
private boolean counter = false;
private long counterMax = 0;
private long resetValue = 0;
private String interval = null;
private Optional<String> interval = Optional.empty();
public RateOption() {}
@@ -85,11 +85,11 @@ public class QueryRequest extends AuthenticatedRequest implements HttpGetRequest
this.resetValue = resetValue;
}
public String getInterval() {
public Optional<String> getInterval() {
return interval;
}
public void setInterval(String interval) {
public void setInterval(Optional<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 = new RateOption();
private RateOption rateOptions = null;
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(rateOptions[x]);
options.setInterval(Optional.of(rateOptions[x]));
break;
case 2:
options.setCounterMax(Long.parseLong(rateOptions[x]));
@@ -24,7 +24,6 @@ public class TimelyProperties {
private int instance = 1;
private int portIncrement = 100;
private String defaultVisibility = null;
private int tagFilterCacheSize = 10000;
public boolean isTest() {
return test;
@@ -92,12 +91,4 @@ public class TimelyProperties {
this.metricsReportIgnoredTags = metricsReportIgnoredTags;
return this;
}
public void setTagFilterCacheSize(int tagFilterCacheSize) {
this.tagFilterCacheSize = tagFilterCacheSize;
}
public int getTagFilterCacheSize() {
return tagFilterCacheSize;
}
}
+1 -2
View File
@@ -7,7 +7,6 @@ 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;
@@ -91,7 +90,7 @@ public class Tag implements Comparable<Tag>, Serializable {
@Override
public int hashCode() {
return new HashCodeBuilder().append(this.key).append(this.value).toHashCode();
return this.toString().hashCode();
}
@Override
+3 -3
View File
@@ -7,9 +7,9 @@
</formats>
<fileSets>
<fileSet>
<directory>timely-datasource/dist</directory>
<outputDirectory>timely-datasource</outputDirectory>
<directory>timely-app/dist</directory>
<outputDirectory>timely-app</outputDirectory>
</fileSet>
</fileSets>
<includeBaseDirectory>false</includeBaseDirectory>
</assembly>
</assembly>
+2 -2
View File
@@ -4,9 +4,9 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>2.1.6-SNAPSHOT</version>
<version>2.1.4-SNAPSHOT</version>
</parent>
<artifactId>timely-datasource</artifactId>
<artifactId>timely-app</artifactId>
<packaging>pom</packaging>
<build>
<plugins>
+2
View File
@@ -0,0 +1,2 @@
node_modules/
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
...require('@grafana/toolkit/src/config/prettier.plugin.config.json'),
};
@@ -1,6 +1,6 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
httpProperties://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -192,10 +192,10 @@
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
httpProperties://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.
limitations under the License.
+18
View File
@@ -0,0 +1,18 @@
//+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
+6
View File
@@ -0,0 +1,6 @@
# 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.
+26
View File
@@ -0,0 +1,26 @@
# 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
+7
View File
@@ -0,0 +1,7 @@
<?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>
@@ -198,4 +198,4 @@
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.
limitations under the License.
+6
View File
@@ -0,0 +1,6 @@
# 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.
+2
View File
@@ -0,0 +1,2 @@
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
+1
View File
@@ -0,0 +1 @@
{"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":""}
+2
View File
@@ -0,0 +1,2 @@
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
+1
View File
@@ -0,0 +1 @@
{"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":""}
+3
View File
@@ -0,0 +1,3 @@
/*! 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
View File
@@ -0,0 +1,87 @@
/*!
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
View File
@@ -0,0 +1 @@
{"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
+40
View File
@@ -0,0 +1,40 @@
{
"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": []
}
}
@@ -2,6 +2,10 @@ div.timely input:focus {
z-index: 1;
}
div.timely-edior-row div.gf-form-inline {
height: 40px !important;
}
div.timely input.form-control {
border-color: rgb(44, 50, 53);
border-top-color: rgb(44, 50, 53);
@@ -52,10 +56,6 @@ div.timely.tag.addtag svg {
color: #62a562;
}
div.timely.tag.deletetag svg {
color: #d9162d;
}
button[title='Move query down'] div svg {
color: #b3bfbd;
}
@@ -75,36 +75,3 @@ button[title='Disable/enable query'] div svg {
button[title='Remove query'] div svg {
color: #d9162d;
}
.queryErrorFieldRow {
margin-bottom: 4px;
}
.queryErrorContainer {
display: flex;
}
.queryErrorIconDiv {
background-color: rgb(209, 14, 92);
padding: 8px;
}
.queryErrorIcon {
height: 16px;
width: 16px;
display: inline-block;
flex-shrink: 0;
line-height: 0;
vertical-align: middle;
fill: rgb(255, 255, 255);
overflow-clip-margin: content-box;
overflow: hidden;
}
.queryErrorText {
text-align: left;
vertical-align: middle;
font-size: 0.857143rem;
font-family: "Roboto Mono", monospace;
padding: 8px;
}
File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,54 @@
$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
View File
@@ -0,0 +1,201 @@
.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;
}
+240
View File
@@ -0,0 +1,240 @@
$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);
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
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
View File
@@ -0,0 +1 @@
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}
+96
View File
@@ -0,0 +1,96 @@
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,32 +1,30 @@
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.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30 h1:hXVi7QKuCQ0E8Yujfu9b0f0RnzZ72efpWvPnZgnJPrE=
github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30/go.mod h1:RNuWDIiGjq5nndL2PyQrndUy9nMLwheA3uWaAV7fe4U=
github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE=
github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw=
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.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
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-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
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.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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=
@@ -37,110 +35,99 @@ github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac h1:9yrT5tmn9Zc
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.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
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 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4=
github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
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.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
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.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
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.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
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.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
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.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/grafana/grafana-plugin-sdk-go v0.260.3 h1:7ri52MhUMouQKf2q9z3RsxSX464FLD3mSJZCv65ux5g=
github.com/grafana/grafana-plugin-sdk-go v0.260.3/go.mod h1:X+6ipUy022esjdomutNjHbH67CbJJzEhkrvvfMbvL8A=
github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8=
github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls=
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg=
github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog=
github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q=
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.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
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 h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
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/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=
github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
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=
@@ -158,10 +145,8 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP
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/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
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=
@@ -171,51 +156,56 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
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.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
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.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
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.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ=
github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
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.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
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 h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w=
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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
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/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.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=
@@ -225,61 +215,58 @@ github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnl
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.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ=
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po=
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/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
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.57.0 h1:qtFISDHKolvIxzSs0gIaiPUPR0Cucb0F2coHC7ZLdps=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0/go.mod h1:Y+Pop1Q6hCOnETWTW4NROK/q1hv50hM7yDaUTjG8lp8=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0 h1:7F3XCD6WYzDkwbi8I8N+oYJWquPVScnRosKGgqjsR8c=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0/go.mod h1:Dk3C0BfIlZDZ5c6eVS7TYiH2vssuyUU3vUsgbrR+5V4=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94=
go.opentelemetry.io/contrib/propagators/jaeger v1.32.0 h1:K/fOyTMD6GELKTIJBaJ9k3ppF2Njt8MeUGBOwfaWXXA=
go.opentelemetry.io/contrib/propagators/jaeger v1.32.0/go.mod h1:ISE6hda//MTWvtngG7p4et3OCngsrTVfl7c6DjN17f8=
go.opentelemetry.io/contrib/samplers/jaegerremote v0.26.0 h1:/SKXyZLAnuj981HVc8G5ZylYK3qD2W6AYR6cJx5kIHw=
go.opentelemetry.io/contrib/samplers/jaegerremote v0.26.0/go.mod h1:cOEzME0M2OKeHB45lJiOKfvUCdg/r75mf7YS5w0tbmE=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0/go.mod h1:JyA0FHXe22E1NeNiHmVp7kFHglnexDQ7uRWDiiJ1hKQ=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
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-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
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-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
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=
@@ -288,98 +275,92 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
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.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
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.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
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.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
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-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
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.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0=
gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o=
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-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79 h1:s1jFTXJryg4a1mew7xv03VZD8N9XjxFhk1o4Js4WvPQ=
google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79/go.mod h1:yiaVoXHpRzHGyxV3o4DktVWY4mSUErTKaeEOq6C3t3U=
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.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
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=
+8
View File
@@ -0,0 +1,8 @@
// 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();
+42
View File
@@ -0,0 +1,42 @@
{
"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,4 +1,4 @@
package backend
package main
import (
"bytes"
@@ -6,32 +6,23 @@ import (
"crypto/tls"
"crypto/x509"
"fmt"
"github.com/hashicorp/go-hclog"
"io"
"io/ioutil"
"net/http"
"os"
"sort"
"strconv"
"strings"
"sync"
"time"
"encoding/json"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/data"
"net/url"
)
"github.com/hashicorp/go-hclog"
// Make sure Datasource implements required interfaces. This is important to do
// since otherwise we will only get a not implemented error response from plugin in
// runtime. In this example datasource instance implements backend.QueryDataHandler,
// backend.CheckHealthHandler interfaces. Plugin should not implement all these
// interfaces - only those which are required for a particular task.
var (
_ backend.QueryDataHandler = (*TimelyDatasource)(nil)
_ backend.CheckHealthHandler = (*TimelyDatasource)(nil)
_ instancemgmt.InstanceDisposer = (*TimelyDatasource)(nil)
"encoding/json"
"io/ioutil"
"net/httpProperties"
"net/url"
)
var (
@@ -52,17 +43,52 @@ type TimelyDatasource struct {
ClientCertificatePath string
ClientKeyPath string
CertificateAuthorityPath string
Mutex sync.Mutex
Mutex *sync.Mutex
}
//type TimelyDatasourceInstanceSettings struct {
type TimelyDatasourceInstanceSettings struct {
}
func newDataSourceInstance(setting backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return &TimelyDatasourceInstanceSettings{}, nil
}
func (s *TimelyDatasourceInstanceSettings) Dispose() {
// Called before creating a new instance to allow plugin authors
// to cleanup.
}
func getServeOpts() datasource.ServeOpts {
// creates a instance manager for your plugin. The function passed
// into `NewInstanceManger` is called when the instance is created
// for the first time or when a datasource configuration changed.
im := datasource.NewInstanceManager(newDataSourceInstance)
ds := &TimelyDatasource{
im: im,
CertPool: nil,
Certificate: nil,
ClientCertificatePath: "",
ClientKeyPath: "",
CertificateAuthorityPath: "",
Mutex: &sync.Mutex{},
}
return datasource.ServeOpts{
CheckHealthHandler: ds,
CallResourceHandler: ds,
QueryDataHandler: ds,
}
}
//func (ds *TimelyDatasource) getSettings(pluginContext backend.PluginContext) (*TimelyDatasourceInstanceSettings, error) {
// iface, err := ds.im.Get(pluginContext)
// if err != nil {
// return nil, err
// }
//
// return iface.(*TimelyDatasourceInstanceSettings), nil
//}
// NewDatasource creates a new datasource instance.
func NewDatasource(_ context.Context, _ backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
return &TimelyDatasource{}, nil
}
// CheckHealth handles health checks sent from Grafana to the plugin.
// The main use case for these health checks is the test button on the
// datasource configuration page which allows users to verify that
@@ -86,7 +112,7 @@ func (td *TimelyDatasource) CallResource(ctx context.Context, request *backend.C
}
var response backend.CallResourceResponse
pluginContext := request.PluginContext
var httpResponse *http.Response
var httpResponse *httpProperties.Response
var timelyDataSourceOptions TimelyDataSourceOptions
err := json.Unmarshal(pluginContext.DataSourceInstanceSettings.JSONData, &timelyDataSourceOptions)
if err != nil {
@@ -99,11 +125,11 @@ func (td *TimelyDatasource) CallResource(ctx context.Context, request *backend.C
logger.Error("Error getting httpClient", "error", err)
return err
}
if strings.HasPrefix(request.Path, "/api/aggregators") ||
strings.HasPrefix(request.Path, "/api/suggest") ||
strings.HasPrefix(request.Path, "/api/search/lookup") {
var timelyUrl *url.URL
if request.Method == "GET" {
var x = strings.Index(request.URL, request.Path)
finalParams := ""
@@ -114,36 +140,26 @@ func (td *TimelyDatasource) CallResource(ctx context.Context, request *backend.C
finalParams = params
}
}
timelyUrl, err = url.Parse("https://" + timelyDataSourceOptions.TimelyHost + ":" + strconv.Itoa(int(timelyDataSourceOptions.HttpsPort)) + request.Path + finalParams)
url, err := url.Parse("https://" + timelyDataSourceOptions.TimelyHost + ":" + timelyDataSourceOptions.HttpsPort + request.Path + finalParams)
if err != nil {
return err
}
httpResponse, err = httpClient.Get(timelyUrl.String())
httpResponse, err = httpClient.Get(url.String())
} else if request.Method == "POST" {
timelyUrl, err = url.Parse("https://" + timelyDataSourceOptions.TimelyHost + ":" + strconv.Itoa(int(timelyDataSourceOptions.HttpsPort)) + request.Path)
url, err := url.Parse("https://" + timelyDataSourceOptions.TimelyHost + ":" + timelyDataSourceOptions.HttpsPort + request.Path)
if err != nil {
return err
}
httpResponse, err = httpClient.Post(timelyUrl.String(), "application/json", bytes.NewReader(request.Body))
httpResponse, err = httpClient.Post(url.String(), "application/json", bytes.NewReader(request.Body))
}
if err != nil {
logger.Error("Error fetching resource", "url", timelyUrl.String(), "error", err)
logger.Error("Error calling for resource", "Path", request.Path, "error", err)
return err
}
if httpResponse == nil {
logger.Error("Error fetching resource, httpResponse null", "url", timelyUrl.String())
return fmt.Errorf("Error fetching resource url:%s, httpResponse null", timelyUrl.String())
}
if httpResponse.StatusCode != 200 {
logger.Error("Error fetching resource", "url", timelyUrl.String(), "responseCode", httpResponse.StatusCode)
return fmt.Errorf("Error fetching resource url:%s responseCode:%d", timelyUrl.String(), httpResponse.StatusCode)
}
bytes, err := io.ReadAll(httpResponse.Body)
bytes, err := ioutil.ReadAll(httpResponse.Body)
if err != nil {
logger.Error("Error reading resource", "url", timelyUrl, "error", err)
logger.Error("Error reading resource", "Path", request.Path, "error", err)
return err
}
response.Status = 200
@@ -161,7 +177,6 @@ func (td *TimelyDatasource) CallResource(ctx context.Context, request *backend.C
// The QueryDataResponse contains a map of RefID to the response for each query, and each response
// contains Frames ([]*Frame).
func (td *TimelyDatasource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
logger.Info("QueryData called with:", "Request", req)
// create response struct
response := backend.NewQueryDataResponse()
@@ -210,7 +225,6 @@ func (td *TimelyDatasource) Query(queryDataRequest *backend.QueryDataRequest, da
Tags: timelyQueryServer.Tags,
Filters: timelyQueryServer.Filters,
ShouldComputeRate: timelyQueryServer.ShouldComputeRate,
RateInterval: timelyQueryServer.RateInterval,
IsCounter: timelyQueryServer.IsCounter,
CounterMax: timelyQueryServer.CounterMax,
CounterResetValue: timelyQueryServer.CounterResetValue,
@@ -229,6 +243,11 @@ func (td *TimelyDatasource) Query(queryDataRequest *backend.QueryDataRequest, da
return nil, err
}
timelyQuery := td.convertTimelyQuery(&timelyQueryForm)
timelyRequest.Queries = append(timelyRequest.Queries, *timelyQuery)
logger.Debug("Query", "timelyRequest", timelyRequest)
var timelyDatasourceOptions TimelyDataSourceOptions
err = json.Unmarshal(queryDataRequest.PluginContext.DataSourceInstanceSettings.JSONData, &timelyDatasourceOptions)
@@ -237,12 +256,7 @@ func (td *TimelyDatasource) Query(queryDataRequest *backend.QueryDataRequest, da
return nil, err
}
timelyQuery := td.convertTimelyQuery(&timelyQueryForm, timelyDatasourceOptions)
timelyRequest.Queries = append(timelyRequest.Queries, *timelyQuery)
logger.Debug("Query", "timelyRequest", timelyRequest)
var httpRequest *http.Request
var httpRequest *httpProperties.Request
httpRequest, err = td.createRequest(timelyDatasourceOptions, timelyRequest)
if err != nil {
logger.Error("Error creating httpRequest", "error", err)
@@ -269,15 +283,8 @@ func (td *TimelyDatasource) Query(queryDataRequest *backend.QueryDataRequest, da
return td.parseResponse(res)
}
// Dispose here tells plugin SDK that plugin wants to clean up resources when a new instance
// created. As soon as datasource settings change detected by SDK old datasource instance will
// be disposed and a new one will be created using NewSampleDatasource factory function.
func (d *TimelyDatasource) Dispose() {
// Clean up datasource instance resources.
}
func (td *TimelyDatasource) createRequest(tdo TimelyDataSourceOptions, timelyRequest TimelyRequest) (*http.Request, error) {
u, err := url.Parse("https://" + tdo.TimelyHost + ":" + strconv.Itoa(int(tdo.HttpsPort)) + "/api/query")
func (td *TimelyDatasource) createRequest(tdo TimelyDataSourceOptions, timelyRequest TimelyRequest) (*httpProperties.Request, error) {
u, err := url.Parse("https://" + tdo.TimelyHost + ":" + tdo.HttpsPort + "/api/query")
if err != nil {
logger.Error("Failed creating query url", "error", err)
return nil, fmt.Errorf("Failed creating query url. error: %v", err)
@@ -287,7 +294,7 @@ func (td *TimelyDatasource) createRequest(tdo TimelyDataSourceOptions, timelyReq
logger.Error("Failed marshaling timelyRequest", "error", err)
return nil, fmt.Errorf("Failed to create request. error: %v", err)
}
req, err := http.NewRequest(http.MethodPost, u.String(), bytes.NewReader(postData))
req, err := httpProperties.NewRequest(httpProperties.MethodPost, u.String(), bytes.NewReader(postData))
if err != nil {
logger.Error("Failed to create request", "error", err)
return nil, fmt.Errorf("Failed to create request. error: %v", err)
@@ -303,9 +310,9 @@ func (td *TimelyDatasource) createRequest(tdo TimelyDataSourceOptions, timelyReq
return req, err
}
func (td *TimelyDatasource) parseResponse(res *http.Response) (*backend.DataResponse, error) {
func (td *TimelyDatasource) parseResponse(res *httpProperties.Response) (*backend.DataResponse, error) {
body, err := io.ReadAll(res.Body)
body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
if err != nil {
return nil, err
@@ -362,7 +369,7 @@ func (td *TimelyDatasource) parseResponse(res *http.Response) (*backend.DataResp
return &response, nil
}
func (td *TimelyDatasource) convertTimelyQuery(timelyQueryForm *TimelyQueryForm, datasourceOptions TimelyDataSourceOptions) *TimelyQuery {
func (td *TimelyDatasource) convertTimelyQuery(timelyQueryForm *TimelyQueryForm) *TimelyQuery {
if timelyQueryForm == nil {
return nil
@@ -378,13 +385,6 @@ func (td *TimelyDatasource) convertTimelyQuery(timelyQueryForm *TimelyQueryForm,
Tsuids: timelyQueryForm.Tsuids,
}
for i := 0; i < len(timelyQueryForm.DatasourceTags); i++ {
tagKey := timelyQueryForm.DatasourceTags[i]
if _, ok := datasourceOptions.DatasourceTags[tagKey]; ok {
timelyQuery.Tags[tagKey] = datasourceOptions.DatasourceTags[tagKey]
}
}
// future work - replace scopedVariables in metric, tags, filters, aggregator
timelyQuery.Aggregator = "avg"
@@ -395,10 +395,16 @@ func (td *TimelyDatasource) convertTimelyQuery(timelyQueryForm *TimelyQueryForm,
if timelyQueryForm.ShouldComputeRate {
timelyQuery.Rate = true
timelyQuery.RateOptions.Interval = timelyQueryForm.RateInterval
timelyQuery.RateOptions.Counter = timelyQueryForm.IsCounter
}
if len(timelyQueryForm.RateInterval) > 0 {
rateInterval, error := strconv.ParseInt(timelyQueryForm.RateInterval, 10, 32)
if error == nil {
timelyQuery.RateOptions.Interval = int32(rateInterval)
}
}
if len(timelyQueryForm.CounterMax) > 0 {
counterMax, error := strconv.ParseInt(timelyQueryForm.CounterMax, 10, 32)
if error == nil {
@@ -435,17 +441,17 @@ func (td *TimelyDatasource) clientSslSettingsChanged(settings TimelyDataSourceOp
certificateAuthorityPath != td.CertificateAuthorityPath
}
func (td *TimelyDatasource) GetHttpClient(settings TimelyDataSourceOptions, useClientCertIfAvailable bool) (*http.Client, error) {
func (td *TimelyDatasource) GetHttpClient(settings TimelyDataSourceOptions, useClientCertIfAvailable bool) (*httpProperties.Client, error) {
// handle call back
logger.Debug("Getting client", "allowInsecureSsl", strconv.FormatBool(settings.AllowInsecureSsl))
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
tr := &httpProperties.Transport{
Proxy: httpProperties.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: settings.AllowInsecureSsl,
},
}
httpClient := &http.Client{
httpClient := &httpProperties.Client{
Transport: tr,
}
@@ -512,3 +518,16 @@ func (td *TimelyDatasource) GetHttpClient(settings TimelyDataSourceOptions, useC
td.Mutex.Unlock()
return httpClient, nil
}
func main() {
// Start listening to requests send from Grafana. This call is blocking so
// it wont finish until Grafana shutsdown the process or the plugin choose
// to exit close down by itself
err := datasource.Serve(getServeOpts())
// Log any error if we could not start the plugin.
if err != nil {
logger.Error("Plugin failed to start", "error", err)
os.Exit(1)
}
}
+102
View File
@@ -0,0 +1,102 @@
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`
}
+183
View File
@@ -0,0 +1,183 @@
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>
);
}
}
+440
View File
@@ -0,0 +1,440 @@
import _ from 'lodash';
import { QueryEditorProps } from '@grafana/data';
import { Input, Select, LegacyForms } from '@grafana/ui';
import React, { Component } from 'react';
import { TimelyDataSource } from './TimelyDataSource';
import { TimelyDataSourceOptions, TimelyErrors, TimelyQueryForm } from './types';
import { SelectableValue } from '@grafana/data/types/select';
import dayjs from 'dayjs';
import { TagEditor } from './TagEditor';
import { AsyncTypeahead, TypeaheadModel } from 'react-bootstrap-typeahead';
const { Switch } = LegacyForms;
export type Props = QueryEditorProps<TimelyDataSource, TimelyQueryForm, TimelyDataSourceOptions>;
interface State {
aggregatorTypes: string[];
errors: TimelyErrors;
query: TimelyQueryForm;
queryOptionsLoading: boolean;
queryOptions: TypeaheadModel[];
}
export class QueryEditor extends Component<Props, State> {
metricArray: string[] = [];
constructor(props: Props) {
super(props);
const defaultQuery: Partial<TimelyQueryForm> = {
metric: '',
alias: '',
aggregator: 'none',
refId: 'A',
queryType: 'metricQuery',
disableDownsampling: false,
downsampleFillPolicy: 'none',
downsampleInterval: '1m',
downsampleAggregator: 'avg',
shouldComputeRate: false,
rateInterval: '1m',
isCounter: false,
tags: {},
};
this.state = {
aggregatorTypes: ['none', 'avg', 'dev', 'max', 'min', 'sum', 'count'],
errors: {
downsample: undefined,
},
query: Object.assign({}, defaultQuery, props.query),
queryOptionsLoading: false,
queryOptions: [],
};
this.getAggregators();
this.getMetrics();
}
shouldComponentUpdate(nextProps: Readonly<Props>, nextState: Readonly<State>, nextContext: any): boolean {
return true;
}
onMetricTextChange = (value: string) => {
this.setState((state, props) => {
var query = Object.assign(state.query, { metric: value });
this.updateQuery(query);
return { query: query };
});
};
onAliasChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
this.setState((state, props) => {
var query = Object.assign(state.query, { alias: value });
this.updateQuery(query);
return { query: query };
});
};
onAggregatorChange = (option: SelectableValue<string>) => {
if (option.value) {
const value = option.value;
this.setState((state, props) => {
var query = Object.assign(state.query, { aggregator: value });
this.updateQuery(query);
return { query: query };
});
}
};
onDownsampleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
this.setState((state, props) => {
var query = Object.assign(state.query, { downsampleInterval: value });
this.updateQuery(query);
return { query: query };
});
};
onDownsampleAggregatorChange = (option: SelectableValue<string>) => {
if (option.value) {
const value = option.value;
this.setState((state, props) => {
var query = Object.assign(state.query, { downsampleAggregator: value });
this.updateQuery(query);
return { query: query };
});
}
};
onDisableDownsamplingChange = (option: React.FormEvent<HTMLInputElement>) => {
const checked = option.currentTarget.checked;
this.setState((state, props) => {
var query = Object.assign(state.query, { disableDownsampling: checked });
this.updateQuery(query);
return { query: query };
});
};
onRateChange = (option: React.FormEvent<HTMLInputElement>) => {
const checked = option.currentTarget.checked;
this.setState((state, props) => {
var query = Object.assign(state.query, { shouldComputeRate: checked });
this.updateQuery(query);
return { query: query };
});
};
onRateIntervalChange = (option: React.FormEvent<HTMLInputElement>) => {
const value = e.target.value;
this.setState((state, props) => {
var query = Object.assign(state.query, { rateInterval: value });
this.updateQuery(query);
return { query: query };
});
};
onCounterChange = (option: React.FormEvent<HTMLInputElement>) => {
const checked = option.currentTarget.checked;
this.setState((state, props) => {
var query = Object.assign(state.query, { isCounter: checked });
this.updateQuery(query);
return { query: query };
});
};
onCounterMaxChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
this.setState((state, props) => {
var query = Object.assign(state.query, { counterMax: value });
this.updateQuery(query);
return { query: query };
});
};
onCounterResetValueChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
this.setState((state, props) => {
var query = Object.assign(state.query, { counterResetValue: value });
this.updateQuery(query);
return { query: query };
});
};
updateQuery = (query: TimelyQueryForm) => {
this.props.onChange(query);
this.props.onRunQuery();
};
updateQueryFromState = () => {
const query = this.state.query;
this.props.onChange(query);
this.props.onRunQuery();
};
validate = () => {
const { disableDownsampling, downsampleInterval } = this.state.query;
if (!disableDownsampling) {
try {
let valid = false;
if (downsampleInterval) {
valid = dayjs('', '').isValid();
}
if (!valid) {
this.setState((state, props) => {
this.setState(
{
errors: {
downsample: "You must supply a downsample interval (e.g. '1m' or '1h').",
},
},
this.updateQueryFromState
);
});
}
} catch (err) {
this.setState(
{
errors: {
downsample: "You must supply a downsample interval (e.g. '1m' or '1h').",
},
},
this.updateQueryFromState
);
}
}
};
getAggregators = () => {
this.props.datasource.getResource('/api/aggregators').then((result: any) => {
if (result && _.isArray(result)) {
this.setState({ aggregatorTypes: result }, this.updateQueryFromState);
}
});
};
getMetrics = () => {
this.props.datasource.getResource('/api/suggest', { type: 'metrics', max: '-1' }).then((result: any) => {
if (result && _.isArray(result)) {
const metrics: string[] = result;
this.metricArray = metrics
.map((value) => {
return value;
})
.concat();
}
});
};
updateTags = (tags: { [key: string]: string }) => {
this.setState((state, props) => {
var query = Object.assign(state.query, { tags: tags });
this.updateQuery(query);
return { query: query };
});
};
handleSearch = (query: string) => {
const results = this.metricArray
.filter((metric) => query === '' || metric.toLowerCase().includes(query.toLowerCase()))
.map((value) => {
return value;
});
this.setState({ queryOptions: results });
};
getInputValue = (id: string): string | null => {
var fullId = 'div#' + id + ' div div input.rbt-input-main';
var inputElement = document.querySelector(fullId);
if (inputElement !== null) {
return (inputElement as HTMLInputElement).value;
}
return null;
};
render() {
var queryEditorId = Math.random().toString(36).substr(2, 9);
const { metric, aggregator, alias } = this.state.query;
const { downsampleInterval, downsampleAggregator, disableDownsampling } = this.state.query;
const { tags } = this.state.query;
const { shouldComputeRate, rateInterval, isCounter, counterResetValue, counterMax } = this.state.query;
const aggregatorOptions: Array<{}> = _.map(this.state.aggregatorTypes, (value: string) => ({
label: value,
value: value,
}));
const { queryOptionsLoading, queryOptions } = this.state;
var multiplier = 7.5;
var metricWidth = 300;
if (metric !== undefined && metric!.length * multiplier > metricWidth) {
metricWidth = Math.ceil(metric!.length * multiplier);
}
var aliasWidth = 175;
if (alias !== undefined && alias!.length * multiplier > aliasWidth) {
aliasWidth = Math.ceil(alias!.length * multiplier);
}
var dynamicStyle =
'div.timely-query input.form-control, div#timelyQuery-' +
queryEditorId +
' { ' +
'width:' +
metricWidth +
'px!important ' +
'}';
dynamicStyle += '#timelyAlias-' + queryEditorId + ' { ' + 'width:' + aliasWidth + 'px!important ' + '}';
return (
<div className="timely-edior-row">
<div className="gf-form-inline">
<style>{dynamicStyle}</style>
<div className="gf-form timely">
<label className="gf-form-label width-10">Metric</label>
<div id={'timelyQuery-' + queryEditorId} className="timely timely-query">
<AsyncTypeahead
id={'timelyQuery-' + queryEditorId + '-Typeahead'}
inputProps={{ spellCheck: false }}
defaultInputValue={metric}
isLoading={queryOptionsLoading}
onSearch={(query) => {
this.setState({ queryOptionsLoading: true });
this.handleSearch(query);
this.setState({ queryOptionsLoading: false });
}}
onChange={(e) => {
var inputValue = this.getInputValue('timelyQuery-' + queryEditorId);
if (inputValue !== null) {
this.onMetricTextChange(inputValue);
}
}}
onBlur={(e) => {
var inputValue = this.getInputValue('timelyQuery-' + queryEditorId);
if (inputValue !== null) {
this.onMetricTextChange(inputValue);
}
}}
onFocus={(e) => {
var inputValue = this.getInputValue('timelyQuery-' + queryEditorId);
if (queryOptions.length === 0 || inputValue === null || inputValue.length === 0) {
this.handleSearch('');
}
}}
options={queryOptions}
selectHintOnEnter={true}
align={'left'}
allowNew={true}
newSelectionPrefix={''}
paginate={true}
paginationText={'more'}
minLength={0}
maxResults={100}
caseSensitive={false}
placeholder={'metric'}
/>
</div>
</div>
<div className="gf-form timely">
<label className="gf-form-label width-5">Alias</label>
<Input
id={'timelyAlias-' + queryEditorId}
className="min-width-10 flex-grow-1"
spellCheck={false}
value={alias || ''}
onChange={this.onAliasChange}
placeholder={'series alias'}
/>
</div>
</div>
<TagEditor tags={tags} parent={this} />
<div className="gf-form-inline">
<div className="gf-form timely">
<label className="gf-form-label width-10">Downsample</label>
<Input
className={'min-width-5 flex-grow-1'}
spellCheck={false}
value={downsampleInterval || ''}
onChange={this.onDownsampleChange}
placeholder={'downsample interval'}
/>
</div>
<div className="gf-form timely">
<label className="gf-form-label width-10">Downsample Aggregator</label>
<Select
className={'min-width-5 flex-grow-1'}
isSearchable={false}
options={aggregatorOptions}
value={downsampleAggregator}
placeholder={'aggregator'}
onChange={this.onDownsampleAggregatorChange}
menuPlacement={'bottom'}
/>
</div>
<div className="gf-form timely">
<Switch
label={'Disable downsampling'}
labelClass="width-10"
checked={disableDownsampling || false}
onChange={this.onDisableDownsamplingChange}
/>
</div>
</div>
<div className="gf-form-inline">
<div className="gf-form timely">
<label className="gf-form-label width-10">All Results Aggregator</label>
<Select
className={'min-width-5 flex-grow-1'}
isSearchable={false}
options={aggregatorOptions}
value={aggregator}
placeholder={'aggregator'}
onChange={this.onAggregatorChange}
menuPlacement={'bottom'}
/>
</div>
<div className="gf-form timely">
<Switch
label={'Rate'}
labelClass="width-5"
checked={shouldComputeRate || false}
onChange={this.onRateChange}
/>
<div hidden={!shouldComputeRate}>
<Input
className={'min-width-6 flex-grow-1'}
spellCheck={false}
value={rateInterval || ''}
onChange={this.onRateIntervalChange}
placeholder={'rate interval'}
/>
<Switch
label={'Counter'}
labelClass="width-10"
checked={isCounter || false}
onChange={this.onCounterChange}
/>
</div>
<div className="gf-form timely" hidden={!shouldComputeRate || !isCounter}>
<label className="gf-form-label width-10">Max Value</label>
<Input
className={'min-width-6 flex-grow-1'}
spellCheck={false}
value={counterMax || ''}
onChange={this.onCounterMaxChange}
placeholder={'max value'}
/>
<label className="gf-form-label width-10">Reset Value</label>
<Input
className={'min-width-6 flex-grow-1'}
spellCheck={false}
value={counterResetValue || ''}
onChange={this.onCounterResetValueChange}
placeholder={'reset value'}
/>
</div>
</div>
</div>
</div>
);
}
}
+519
View File
@@ -0,0 +1,519 @@
import React, { Component } from 'react';
import { QueryEditor } from './QueryEditor';
import { withStyles } from '@material-ui/core/styles';
import { Tooltip } from '@material-ui/core';
import { Icon } from '@grafana/ui';
import _ from 'lodash';
import { AsyncTypeahead, TypeaheadModel } from 'react-bootstrap-typeahead';
export interface Props {
tags: { [key: string]: string };
parent: QueryEditor;
}
interface State {
tags: Tag[];
tagKeyOptionsLoading: boolean;
tagKeyOptions: TypeaheadModel[];
tagValueOptionsLoading: boolean;
tagValueOptions: TypeaheadModel[];
}
interface Tag {
key: string;
value: string;
editing: boolean;
errors: string[] | undefined;
}
const HtmlTooltip = withStyles((theme) => ({
tooltip: {
backgroundColor: '#f5f5f9',
color: 'rgba(0, 0, 0, 0.87)',
maxWidth: 220,
fontSize: theme.typography.pxToRem(12),
border: '1px solid #dadde9',
},
}))(Tooltip);
export class TagEditor extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
tags: Object.entries(props.tags)
.map(([key, value]) => ({
key: key,
value: value,
editing: false,
errors: undefined,
}))
.concat(),
tagKeyOptionsLoading: false,
tagKeyOptions: [],
tagValueOptionsLoading: false,
tagValueOptions: [],
};
}
shouldComponentUpdate(nextProps: Readonly<Props>, nextState: Readonly<State>, nextContext: any): boolean {
return true;
}
validateTags = (tags: Tag[], tagNumber: number): boolean => {
var count = new Map<string, number>();
var anyErrors = false;
tags.forEach((tag) => {
var n = count.get(tag.key);
if (n === undefined) {
count.set(tag.key, 1);
} else {
count.set(tag.key, n! + 1);
}
});
var tagsToValidate: Tag[];
if (tagNumber === undefined) {
tagsToValidate = tags;
} else {
tagsToValidate = tags.filter((t, i) => i === tagNumber);
}
tagsToValidate.forEach((tag, i) => {
tag.errors = [];
if (tag.key.length > 0 && count.get(tag.key)! > 1) {
tag.errors.push("duplicate tag key '" + tag.key + "'");
anyErrors = true;
}
if (tag.key.length === 0) {
tag.errors.push('tag key can not be empty');
anyErrors = true;
}
if (tag.value.length === 0) {
tag.errors.push('tag value can not be empty');
anyErrors = true;
}
if (tag.errors.length === 0) {
tag.errors = undefined;
}
});
return anyErrors;
};
addTag = () => {
this.setState((state, props) => {
const stateTags = state.tags;
var tags = [
...stateTags,
{
key: '',
value: '',
editing: true,
errors: ['tag key can not be empty', 'tag value can not be empty'],
},
];
return { tags: tags };
});
};
removeTag = (tagNumber: number) => {
this.setState((state, props) => {
const tags = state.tags;
tags.splice(tagNumber, 1);
this.updateTags(tags);
return { tags: tags };
});
};
beginEdit = (tagNumber: number) => {
this.setState((state, props) => {
const tags = state.tags;
var tag = tags.filter((t, i) => i === tagNumber).pop();
if (tag !== undefined) {
tag.editing = true;
}
return { tags: tags };
});
};
endEdit = (tagNumber: number) => {
this.setState((state, props) => {
const tags = state.tags;
var tag = tags.filter((t, i) => i === tagNumber).pop();
if (tag !== undefined && this.validateTags(tags, tagNumber) === false) {
tag.editing = false;
this.updateTags(tags);
}
return { tags: tags };
});
};
updateTagKey = (tagNumber: number, newKey: string) => {
this.setState((state, props) => {
var tags = state.tags;
var tag = tags.filter((t, i) => i === tagNumber).pop();
if (tag !== undefined) {
tag.key = newKey;
}
this.validateTags(tags, tagNumber);
return { tags: tags };
});
};
updateTagValue = (tagNumber: number, newValue: string) => {
this.setState((state, props) => {
var tags = state.tags;
var tag = tags.filter((t, i) => i === tagNumber).pop();
if (tag !== undefined) {
tag.value = newValue;
}
this.validateTags(tags, tagNumber);
return { tags: tags };
});
};
updateTags = (tags: Tag[]) => {
var entries = Object.fromEntries([...tags.values()].map((tag) => [tag.key, tag.value]).concat());
this.props.parent.updateTags(entries);
};
handleTagKeySearch = (query: string, metric: string | undefined) => {
if (metric !== undefined) {
this.props.parent.props.datasource
.postResource('/api/suggest', {
type: 'tagk',
m: metric,
max: '1000',
})
.then((result: any) => {
if (result && _.isArray(result)) {
const tagKeyArray: string[] = result;
var tags = this.state.tags;
// find all tag keys that are being used in non-edited tags
var existingTags = tags
.filter((t) => t.editing === false)
.map((t) => {
return t.key;
})
.concat();
// exclude keys that are bing used
var filteredResults = tagKeyArray.filter((t) => {
return existingTags.find((existing) => t === existing) === undefined;
});
// exclude keys that don't match the search (if there is one)
filteredResults = filteredResults
.filter((tagKey) => query === '' || tagKey.toLowerCase().includes(query.toLowerCase()))
.map((value) => {
return value;
});
this.setState({ tagKeyOptions: filteredResults });
}
});
}
};
handleTagValueSearch = (query: string, metric: string | undefined, tagKey: string | undefined) => {
if (metric !== undefined && tagKey !== undefined) {
this.props.parent.props.datasource
.postResource('/api/suggest', {
type: 'tagv',
m: metric,
t: tagKey,
max: '1000',
})
.then((result: any) => {
if (result && _.isArray(result)) {
const tagValueArray: string[] = ['.*', ...result];
const filteredResults = tagValueArray
.filter((tagValue) => query === '' || tagValue.toLowerCase().includes(query.toLowerCase()))
.map((value) => {
return value;
});
this.setState({ tagValueOptions: filteredResults });
}
});
}
};
getInputValue = (id: string): string | null => {
var fullId = 'div#' + id + ' div div input.rbt-input-main';
var inputElement = document.querySelector(fullId);
if (inputElement !== null) {
return (inputElement as HTMLInputElement).value;
}
return null;
};
render() {
const { tagKeyOptionsLoading, tagKeyOptions, tagValueOptionsLoading, tagValueOptions } = this.state;
var { tags } = this.state;
var tagEditorId = Math.random().toString(36).substr(2, 9);
var lastSearchMetric: string;
const { metric } = this.props.parent.state.query;
var allowAddNewTag = tags.filter((t) => t.editing === true).length === 0;
return (
<div className="gf-form-inline">
<div className="gf-form timely">
<label className="gf-form-label width-10">Tags</label>
{[...tags.values()].map((tag, tagNum) => (
<div key={tagNum.toString()} id={'timelytag-' + tagNum.toString()}>
<div hidden={tag.editing}>
<label className="gf-form-label">
{tag.key}&nbsp;=&nbsp;{tag.value}
<div className="timely tag edit">
<HtmlTooltip title={'edit tag'} placement={'bottom'}>
<Icon
name="edit"
tabIndex={0}
onClick={(e) => {
this.beginEdit(tagNum);
}}
onKeyPress={(e) => {
if (e.key === 'Enter') {
this.beginEdit(tagNum);
}
}}
/>
</HtmlTooltip>
</div>
<div className="timely tag delete">
<HtmlTooltip title={'delete tag'} placement={'bottom'}>
<Icon
name="trash-alt"
tabIndex={0}
onClick={(e) => {
this.removeTag(tagNum);
}}
onKeyPress={(e) => {
if (e.key === 'Enter') {
this.removeTag(tagNum);
}
}}
/>
</HtmlTooltip>
</div>
</label>
</div>
<div className="gf-form" hidden={!tag.editing}>
<div
id={'timelyTagKey-' + tagEditorId + '-' + tagNum.toString()}
className="timely timely-tag-key"
onMouseLeave={(e) => {
var inputValue = this.getInputValue('timelyTagKey-' + tagEditorId + '-' + tagNum.toString());
if (inputValue !== null) {
this.updateTagKey(tagNum, inputValue);
}
}}
>
<AsyncTypeahead
id={'timelyTagKey-' + tagEditorId + '-Typeahead'}
selected={[tag.key]}
isLoading={tagKeyOptionsLoading}
inputProps={{ spellCheck: false }}
onSearch={(query) => {
this.setState({ tagKeyOptionsLoading: true });
lastSearchMetric = metric!;
this.handleTagKeySearch(query, metric);
this.setState({ tagKeyOptionsLoading: false });
}}
onChange={(e) => {
var inputValue = this.getInputValue('timelyTagKey-' + tagEditorId + '-' + tagNum.toString());
if (inputValue !== null) {
this.updateTagKey(tagNum, inputValue);
}
}}
onBlur={(e) => {
var inputValue = this.getInputValue('timelyTagKey-' + tagEditorId + '-' + tagNum.toString());
if (inputValue !== null) {
this.updateTagKey(tagNum, inputValue);
}
}}
onFocus={(e) => {
var inputValue = this.getInputValue('timelyTagKey-' + tagEditorId + '-' + tagNum.toString());
if (
tagKeyOptions.length === 0 ||
inputValue === null ||
inputValue.length === 0 ||
metric !== lastSearchMetric
) {
this.setState({ tagKeyOptionsLoading: true });
lastSearchMetric = metric!;
this.handleTagKeySearch('', metric);
this.setState({ tagKeyOptionsLoading: false });
}
}}
onKeyDown={(e) => {
var inputValue = this.getInputValue('timelyTagKey-' + tagEditorId + '-' + tagNum.toString());
if (
tagKeyOptions.length === 0 ||
inputValue === null ||
inputValue.length === 0 ||
metric !== lastSearchMetric
) {
this.setState({ tagKeyOptionsLoading: true });
lastSearchMetric = metric!;
this.handleTagKeySearch('', metric);
this.setState({ tagKeyOptionsLoading: false });
}
}}
autoFocus={tag.key.length === 0}
options={tagKeyOptions}
selectHintOnEnter={false}
align={'left'}
allowNew={true}
newSelectionPrefix={''}
paginate={true}
paginationText={'more'}
minLength={0}
maxResults={100}
caseSensitive={false}
placeholder={'key'}
/>
</div>
<div
id={'timelyTagValue-' + tagEditorId + '-' + tagNum.toString()}
className="timely timely-tag-value"
onMouseLeave={(e) => {
var inputValue = this.getInputValue('timelyTagValue-' + tagEditorId + '-' + tagNum.toString());
if (inputValue !== null) {
this.updateTagValue(tagNum, inputValue);
}
}}
>
<AsyncTypeahead
id={'timelyTagValue-' + tagEditorId + '-Typeahead'}
selected={[tag.value]}
isLoading={tagValueOptionsLoading}
inputProps={{ spellCheck: false }}
onSearch={(query) => {
this.setState({ tagValueOptionsLoading: true });
this.handleTagValueSearch(query, metric, tag.key);
this.setState({ tagValueOptionsLoading: false });
}}
onChange={(e) => {
var inputValue = this.getInputValue('timelyTagValue-' + tagEditorId + '-' + tagNum.toString());
if (inputValue !== null) {
this.updateTagValue(tagNum, inputValue);
}
}}
onBlur={(e) => {
var inputValue = this.getInputValue('timelyTagValue-' + tagEditorId + '-' + tagNum.toString());
if (inputValue !== null) {
this.updateTagValue(tagNum, inputValue);
}
}}
onFocus={(e) => {
var inputValue = this.getInputValue('timelyTagValue-' + tagEditorId + '-' + tagNum.toString());
if (tagValueOptions.length === 0 || inputValue === null || inputValue.length === 0) {
this.setState({ tagValueOptionsLoading: true });
this.handleTagValueSearch('', metric, tag.key);
this.setState({ tagValueOptionsLoading: false });
}
}}
onKeyDown={(e) => {
var inputValue = this.getInputValue('timelyTagValue-' + tagEditorId + '-' + tagNum.toString());
if (tagValueOptions.length === 0 || inputValue === null || inputValue.length === 0) {
this.setState({ tagValueOptionsLoading: true });
this.handleTagValueSearch('', metric, tag.key);
this.setState({ tagValueOptionsLoading: false });
}
}}
options={tagValueOptions}
selectHintOnEnter={false}
align={'left'}
allowNew={true}
newSelectionPrefix={''}
paginate={true}
paginationText={'more'}
minLength={0}
maxResults={100}
caseSensitive={false}
placeholder={'value'}
/>
</div>
<label className="gf-form-label max-width-5 flex-shrink-1">
{tag.errors !== undefined && (
<div className="timely tag error">
<HtmlTooltip
title={
<React.Fragment>
<ul>
{tag.errors.map((error) => {
return <li key={error}>{error}</li>;
})}
</ul>
</React.Fragment>
}
placement={'bottom'}
>
<Icon name="exclamation-triangle" />
</HtmlTooltip>
</div>
)}
{tag.errors === undefined && (
<div className="timely tag save">
<HtmlTooltip title={'save tag'} placement={'bottom'}>
<Icon
name="save"
tabIndex={0}
onClick={(e) => {
this.endEdit(tagNum);
}}
onKeyPress={(e) => {
if (e.key === 'Enter') {
this.endEdit(tagNum);
}
}}
/>
</HtmlTooltip>
</div>
)}
<div className="timely tag delete">
<HtmlTooltip title={'delete tag'} placement={'bottom'}>
<Icon
name="trash-alt"
tabIndex={0}
onClick={(e) => {
this.removeTag(tagNum);
}}
onKeyPress={(e) => {
if (e.key === 'Enter') {
this.removeTag(tagNum);
}
}}
/>
</HtmlTooltip>
</div>
</label>
</div>
</div>
))}
<div className="gf-form" hidden={!allowAddNewTag}>
<label className="gf-form-label">
<div className="timely tag addtag">
<HtmlTooltip title={'add tag'} placement={'bottom'}>
<Icon
name="plus"
tabIndex={0}
onClick={(e) => {
this.addTag();
}}
onKeyPress={(e) => {
if (e.key === 'Enter') {
this.addTag();
}
}}
/>
</HtmlTooltip>
</div>
</label>
</div>
</div>
</div>
);
}
}
@@ -1,28 +1,24 @@
import _ from 'lodash';
import {
AdHocVariableFilter,
DataFrame,
DataQuery,
DataQueryRequest,
DataQueryResponse,
DataSourceInstanceSettings,
Field,
Labels,
MetricFindValue,
ScopedVars, TestDataSourceResponse,
} from '@grafana/data';
import { DataQuery } from '@grafana/schema';
import { DataSourceWithBackend, HealthCheckResult, getTemplateSrv } from '@grafana/runtime';
import { DataSourceWithBackend, getTemplateSrv } from '@grafana/runtime';
import { TimelyDataSourceOptions, TimelyQueryForm } from './types';
import { Observable } from 'rxjs';
import { HealthCheckResult } from '@grafana/runtime/utils/DataSourceWithBackend';
import { DataFrame } from '@grafana/data/types/dataFrame';
import { ScopedVars } from '@grafana/data/types/ScopedVars';
import { map } from 'rxjs/operators';
export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, TimelyDataSourceOptions> {
instanceSettings: DataSourceInstanceSettings<TimelyDataSourceOptions>
constructor(instanceSettings: DataSourceInstanceSettings<TimelyDataSourceOptions>) {
super(instanceSettings);
this.instanceSettings = instanceSettings;
}
/**
@@ -30,9 +26,9 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
*/
query(request: DataQueryRequest<TimelyQueryForm>): Observable<DataQueryResponse> {
// match query refId to TimelyQueryForm for correlation to results
let targetIndex: { [key: string]: TimelyQueryForm } = {};
var targetIndex: { [key: string]: TimelyQueryForm } = {};
request.targets.forEach((target) => {
let query = target as TimelyQueryForm;
var query = target as TimelyQueryForm;
targetIndex[query.refId] = query;
});
@@ -42,8 +38,8 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
return super.query(request).pipe(
map((dataQueryResponse) => {
dataQueryResponse.data.forEach((data) => {
let dataFrame = data as DataFrame;
let currentQuery = targetIndex[dataFrame.refId!];
var dataFrame = data as DataFrame;
var currentQuery = targetIndex[dataFrame.refId!];
// prevent grafana from prepending the dataFrame name
// to the series names by naming them all the same
dataFrame.fields.forEach((field) => {
@@ -77,12 +73,12 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
}
setSeriesName(query: TimelyQueryForm, scopedVars: ScopedVars, field: Field, alias: string | undefined) {
let title: string | null = null;
var title: string | null = null;
if (alias === undefined || alias === '') {
if (field.labels === undefined) {
title = query.metric!;
} else {
let singleTagName = this.getSingleLabelName(field.labels);
var singleTagName = this.getSingleLabelName(field.labels);
if (singleTagName === null) {
title = query.metric! + this.joinLabels(field.labels);
} else {
@@ -90,7 +86,7 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
}
}
} else {
let newScopedVars = _.clone(scopedVars || {});
var newScopedVars = _.clone(scopedVars || {});
for (const labelKey in field.labels) {
newScopedVars['tag_' + labelKey] = {
text: field.labels[labelKey],
@@ -108,8 +104,8 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
};
}
applyTemplateVariables(query: DataQuery, scopedVars: ScopedVars, filters?: AdHocVariableFilter[]) {
let timelyQuery = query as TimelyQueryForm;
applyTemplateVariables(query: DataQuery): DataQuery {
var timelyQuery = query as TimelyQueryForm;
if (timelyQuery.metric !== undefined) {
timelyQuery.metric = getTemplateSrv().replace(timelyQuery.metric);
for (let tagsKey in timelyQuery.tags) {
@@ -141,7 +137,7 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
});
}
let interpolated;
var interpolated;
try {
interpolated = getTemplateSrv().replace(query);
} catch (err) {
@@ -150,22 +146,22 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
});
}
let responseTransform = function (result: string[]): MetricFindValue[] {
var responseTransform = function (result: string[]): MetricFindValue[] {
return _.map(result, function (value) {
let mfv: MetricFindValue = {
var mfv: MetricFindValue = {
text: value,
};
return mfv;
}).concat();
};
let metrics_regex = /metrics\((.*)\)/;
let tag_names_suggest_regex = /suggest_tagk\((.*)\)/;
let tag_values_suggest_regex = /suggest_tagv\((.*?),\s?(.*)\)/;
let tag_names_regex = /tag_names\((.*)\)/;
let tag_values_regex = /tag_values\((.*?),\s?(.*)\)/;
var metrics_regex = /metrics\((.*)\)/;
var tag_names_suggest_regex = /suggest_tagk\((.*)\)/;
var tag_values_suggest_regex = /suggest_tagv\((.*?),\s?(.*)\)/;
var tag_names_regex = /tag_names\((.*)\)/;
var tag_values_regex = /tag_values\((.*?),\s?(.*)\)/;
let metrics_query = interpolated.match(metrics_regex);
var metrics_query = interpolated.match(metrics_regex);
if (metrics_query) {
return this._performSuggestQuery({
type: 'metrics',
@@ -174,7 +170,7 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
}).then(responseTransform);
}
let tag_names_suggest_query = interpolated.match(tag_names_suggest_regex);
var tag_names_suggest_query = interpolated.match(tag_names_suggest_regex);
if (tag_names_suggest_query) {
return this._performSuggestQuery({
type: 'tagk',
@@ -183,7 +179,7 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
}).then(responseTransform);
}
let tag_values_suggest_query = interpolated.match(tag_values_suggest_regex);
var tag_values_suggest_query = interpolated.match(tag_values_suggest_regex);
if (tag_values_suggest_query) {
return this._performSuggestQuery({
type: 'tagv',
@@ -193,7 +189,7 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
}).then(responseTransform);
}
let tag_names_query = interpolated.match(tag_names_regex);
var tag_names_query = interpolated.match(tag_names_regex);
if (tag_names_query) {
return this._performSuggestQuery({
type: 'tagk',
@@ -202,7 +198,7 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
}).then(responseTransform);
}
let tag_values_query = interpolated.match(tag_values_regex);
var tag_values_query = interpolated.match(tag_values_regex);
if (tag_values_query) {
return this._performSuggestQuery({
type: 'tagv',
@@ -223,18 +219,8 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
}
// DataSourceApi
testDatasource(): Promise<TestDataSourceResponse> {
try {
return this.getResource('/api/suggest', { type: 'metrics', max: '-1' }).then((result: any) => {
if (result && _.isArray(result)) {
return Promise.resolve({ message: 'Data source is working', status: 'Data source is working' });
} else {
return Promise.reject({ message: 'Data source failed: ' + result.message, status: 'Data source failed' });
}
});
} catch (e) {
return Promise.reject({ message: 'Data source failed', status: 'Data source failed', error: e });
}
testDatasource(): Promise<any> {
return super.testDatasource();
}
// DataSourceApi
@@ -244,7 +230,7 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
const metrics: string[] = result;
return metrics
.map((value) => {
let mfv: MetricFindValue = {
var mfv: MetricFindValue = {
text: value,
};
return mfv;
@@ -263,7 +249,7 @@ export class TimelyDataSource extends DataSourceWithBackend<TimelyQueryForm, Tim
const metrics: string[] = result;
return metrics
.map((value) => {
let mfv: MetricFindValue = {
var mfv: MetricFindValue = {
text: value,
};
return mfv;
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+5
View File
@@ -0,0 +1,5 @@
describe('placeholder test', () => {
it('should return true', () => {
expect(true).toBeTruthy();
});
});
@@ -1,15 +1,15 @@
import { DataSourcePlugin } from '@grafana/data';
import { TimelyDataSource } from './TimelyDataSource';
import { ConfigEditor } from './components/ConfigEditor';
import { QueryEditor } from './components/QueryEditor';
import { ConfigEditor } from './ConfigEditor';
import { QueryEditor } from './QueryEditor';
import { TimelyDataSourceOptions, TimelyQueryForm } from './types';
import 'static/css/timely-bootstrap.css';
import 'static/css/timely.css';
import { loadPluginCss } from '@grafana/runtime';
loadPluginCss({
dark: 'plugins/timely-datasource/styles/dark.css',
light: 'plugins/timely-datasource/styles/light.css',
dark: 'plugins/nsa-timely-datasource/styles/dark.css',
light: 'plugins/nsa-timely-datasource/styles/light.css',
});
export const plugin = new DataSourcePlugin<TimelyDataSource, TimelyQueryForm, TimelyDataSourceOptions>(TimelyDataSource)
@@ -1,19 +1,18 @@
{
"$schema": "https://raw.githubusercontent.com/grafana/grafana/main/docs/sources/developers/plugins/plugin.schema.json",
"type": "datasource",
"name": "Timely",
"id": "timely-datasource",
"id": "nsa-timely-datasource",
"category": "tsdb",
"metrics": true,
"backend": true,
"alerting": true,
"executable": "timely_datasource",
"executable": "timely_datasource_backend",
"info": {
"description": "Datasource for Timely",
"description": "Open source time series database backed by Accumulo",
"author": {
"name": "National Security Agency"
},
"keywords": ["datasource"],
"keywords": ["Simple"],
"logos": {
"small": "static/img/timely_square_small.png",
"large": "static/img/timely_square_large.png"
@@ -33,7 +32,9 @@
"updated": "%TODAY%"
},
"dependencies": {
"grafanaDependency": ">=10.0.0",
"classnames": "2.2.6",
"slate-plain-serializer": "0.7.10",
"grafanaVersion": "6.5.x",
"plugins": []
}
}
@@ -2,6 +2,10 @@ div.timely input:focus {
z-index: 1;
}
div.timely-edior-row div.gf-form-inline {
height: 40px !important;
}
div.timely input.form-control {
border-color: rgb(44, 50, 53);
border-top-color: rgb(44, 50, 53);
@@ -52,10 +56,6 @@ div.timely.tag.addtag svg {
color: #62a562;
}
div.timely.tag.deletetag svg {
color: #d9162d;
}
button[title='Move query down'] div svg {
color: #b3bfbd;
}
@@ -75,36 +75,3 @@ button[title='Disable/enable query'] div svg {
button[title='Remove query'] div svg {
color: #d9162d;
}
.queryErrorFieldRow {
margin-bottom: 4px;
}
.queryErrorContainer {
display: flex;
}
.queryErrorIconDiv {
background-color: rgb(209, 14, 92);
padding: 8px;
}
.queryErrorIcon {
height: 16px;
width: 16px;
display: inline-block;
flex-shrink: 0;
line-height: 0;
vertical-align: middle;
fill: rgb(255, 255, 255);
overflow-clip-margin: content-box;
overflow: hidden;
}
.queryErrorText {
text-align: left;
vertical-align: middle;
font-size: 0.857143rem;
font-family: "Roboto Mono", monospace;
padding: 8px;
}
File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,54 @@
$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;
}
}
@@ -0,0 +1,201 @@
.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;
}
@@ -0,0 +1,240 @@
$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);
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -51,11 +51,3 @@ div.timely mark.rbt-highlight-text {
background: linear-gradient(90deg, #56585c, #4c5057);
color: #ff0;
}
.queryErrorFieldRow {
background-color: rgb(34, 37, 43);
}
.queryErrorIcon {
color: rgb(255, 255, 255);
}
@@ -50,7 +50,3 @@ div.timely mark.rbt-highlight-text {
background: linear-gradient(90deg, #bfc0c1, #abadaf);
color: #ff0;
}
.queryErrorFieldRow {
background-color: rgb(244, 245, 245);
}
@@ -1,5 +1,4 @@
import { DataSourceJsonData, ScopedVars } from '@grafana/data';
import { DataQuery } from '@grafana/schema';
import { DataQuery, DataSourceJsonData, ScopedVars } from '@grafana/data';
export interface TimelyQueryForm extends DataQuery {
metric?: string;
@@ -9,7 +8,6 @@ export interface TimelyQueryForm extends DataQuery {
downsampleInterval?: string;
downsampleAggregator?: string;
tags: { [key: string]: string };
datasourceTags: string[];
shouldComputeRate?: boolean;
rateInterval?: string;
isCounter?: boolean;
@@ -25,19 +23,17 @@ export interface TimelyQueryForm extends DataQuery {
*/
export interface TimelyDataSourceOptions extends DataSourceJsonData {
timelyHost: string;
httpsPort: number;
httpsPort: string;
oauthPassThru: boolean;
useClientCertWhenOAuthMissing: boolean;
clientCertificatePath: string;
clientKeyPath: string;
certificateAuthorityPath: string;
allowInsecureSsl: boolean;
datasourceTags: { [key: string]: string };
}
export interface TimelyErrors {
downsample?: string;
rateInterval?: string;
}
export interface SearchLookupResults {
+15
View File
@@ -0,0 +1,15 @@
{
"extends": "@grafana/toolkit/src/config/tsconfig.plugin.json",
"include": ["src", "types"],
"paths": {
"@grafana/slate-react": ["./node_modules/@types/slate-react"]
},
"compilerOptions": {
"esModuleInterop": true,
"rootDir": "./src",
"baseUrl": "./src",
"typeRoots": ["./node_modules/@types"],
"jsx": "react",
"allowJs": true
}
}
File diff suppressed because it is too large. Load diff
@@ -1,3 +0,0 @@
{
"version": "5.12.4"
}
@@ -1,31 +0,0 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-eslint-config
*/
{
"extends": ["@grafana/eslint-config"],
"root": true,
"rules": {
"react/prop-types": "off"
},
"overrides": [
{
"plugins": ["deprecation"],
"files": ["src/**/*.{ts,tsx}"],
"rules": {
"deprecation/deprecation": "warn"
},
"parserOptions": {
"project": "./tsconfig.json"
}
},
{
"files": ["./tests/**/*"],
"rules": {
"react-hooks/rules-of-hooks": "off"
}
}
]
}
@@ -1,16 +0,0 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in .config/README.md
*/
module.exports = {
endOfLine: 'auto',
printWidth: 120,
trailingComma: 'es5',
semi: true,
jsxSingleQuote: false,
singleQuote: true,
useTabs: false,
tabWidth: 2,
};
@@ -1,77 +0,0 @@
ARG grafana_version=latest
ARG grafana_image=grafana-enterprise
FROM grafana/${grafana_image}:${grafana_version}
ARG anonymous_auth_enabled=true
ARG development=false
ARG TARGETARCH
ARG GO_VERSION=1.21.6
ARG GO_ARCH=${TARGETARCH:-amd64}
ENV DEV "${development}"
# Make it as simple as possible to access the grafana instance for development purposes
# Do NOT enable these settings in a public facing / production grafana instance
ENV GF_AUTH_ANONYMOUS_ORG_ROLE "Admin"
ENV GF_AUTH_ANONYMOUS_ENABLED "${anonymous_auth_enabled}"
ENV GF_AUTH_BASIC_ENABLED "false"
# Set development mode so plugins can be loaded without the need to sign
ENV GF_DEFAULT_APP_MODE "development"
LABEL maintainer="Grafana Labs <[email protected]>"
ENV GF_PATHS_HOME="/usr/share/grafana"
WORKDIR $GF_PATHS_HOME
USER root
# Installing supervisor and inotify-tools
RUN if [ "${development}" = "true" ]; then \
if grep -i -q alpine /etc/issue; then \
apk add supervisor inotify-tools git; \
elif grep -i -q ubuntu /etc/issue; then \
DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -y supervisor inotify-tools git && \
rm -rf /var/lib/apt/lists/*; \
else \
echo 'ERROR: Unsupported base image' && /bin/false; \
fi \
fi
COPY supervisord/supervisord.conf /etc/supervisor.d/supervisord.ini
COPY supervisord/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Installing Go
RUN if [ "${development}" = "true" ]; then \
curl -O -L https://golang.org/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \
rm -rf /usr/local/go && \
tar -C /usr/local -xzf go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \
echo "export PATH=$PATH:/usr/local/go/bin:~/go/bin" >> ~/.bashrc && \
rm -f go${GO_VERSION}.linux-${GO_ARCH}.tar.gz; \
fi
# Installing delve for debugging
RUN if [ "${development}" = "true" ]; then \
/usr/local/go/bin/go install github.com/go-delve/delve/cmd/dlv@latest; \
fi
# Installing mage for plugin (re)building
RUN if [ "${development}" = "true" ]; then \
git clone https://github.com/magefile/mage; \
cd mage; \
export PATH=$PATH:/usr/local/go/bin; \
go run bootstrap.go; \
fi
# Inject livereload script into grafana index.html
RUN sed -i 's|</body>|<script src="http://localhost:35729/livereload.js"></script></body>|g' /usr/share/grafana/public/views/index.html
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
-164
View File
@@ -1,164 +0,0 @@
# Default build configuration by Grafana
**This is an auto-generated directory and is not intended to be changed! ⚠️**
The `.config/` directory holds basic configuration for the different tools
that are used to develop, test and build the project. In order to make it updates easier we ask you to
not edit files in this folder to extend configuration.
## How to extend the basic configs?
Bear in mind that you are doing it at your own risk, and that extending any of the basic configuration can lead
to issues around working with the project.
### Extending the ESLint config
Edit the `.eslintrc` file in the project root in order to extend the ESLint configuration.
**Example:**
```json
{
"extends": "./.config/.eslintrc",
"rules": {
"react/prop-types": "off"
}
}
```
---
### Extending the Prettier config
Edit the `.prettierrc.js` file in the project root in order to extend the Prettier configuration.
**Example:**
```javascript
module.exports = {
// Prettier configuration provided by Grafana scaffolding
...require('./.config/.prettierrc.js'),
semi: false,
};
```
---
### Extending the Jest config
There are two configuration in the project root that belong to Jest: `jest-setup.js` and `jest.config.js`.
**`jest-setup.js`:** A file that is run before each test file in the suite is executed. We are using it to
set up the Jest DOM for the testing library and to apply some polyfills. ([link to Jest docs](https://jestjs.io/docs/configuration#setupfilesafterenv-array))
**`jest.config.js`:** The main Jest configuration file that extends the Grafana recommended setup. ([link to Jest docs](https://jestjs.io/docs/configuration))
#### ESM errors with Jest
A common issue with the current jest config involves importing an npm package that only offers an ESM build. These packages cause jest to error with `SyntaxError: Cannot use import statement outside a module`. To work around this, we provide a list of known packages to pass to the `[transformIgnorePatterns](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring)` jest configuration property. If need be, this can be extended in the following way:
```javascript
process.env.TZ = 'UTC';
const { grafanaESModules, nodeModulesToTransform } = require('./config/jest/utils');
module.exports = {
// Jest configuration provided by Grafana
...require('./.config/jest.config'),
// Inform jest to only transform specific node_module packages.
transformIgnorePatterns: [nodeModulesToTransform([...grafanaESModules, 'packageName'])],
};
```
---
### Extending the TypeScript config
Edit the `tsconfig.json` file in the project root in order to extend the TypeScript configuration.
**Example:**
```json
{
"extends": "./.config/tsconfig.json",
"compilerOptions": {
"preserveConstEnums": true
}
}
```
---
### Extending the Webpack config
Follow these steps to extend the basic Webpack configuration that lives under `.config/`:
#### 1. Create a new Webpack configuration file
Create a new config file that is going to extend the basic one provided by Grafana.
It can live in the project root, e.g. `webpack.config.ts`.
#### 2. Merge the basic config provided by Grafana and your custom setup
We are going to use [`webpack-merge`](https://github.com/survivejs/webpack-merge) for this.
```typescript
// webpack.config.ts
import type { Configuration } from 'webpack';
import { merge } from 'webpack-merge';
import grafanaConfig from './.config/webpack/webpack.config';
const config = async (env): Promise<Configuration> => {
const baseConfig = await grafanaConfig(env);
return merge(baseConfig, {
// Add custom config here...
output: {
asyncChunks: true,
},
});
};
export default config;
```
#### 3. Update the `package.json` to use the new Webpack config
We need to update the `scripts` in the `package.json` to use the extended Webpack configuration.
**Update for `build`:**
```diff
-"build": "webpack -c ./.config/webpack/webpack.config.ts --env production",
+"build": "webpack -c ./webpack.config.ts --env production",
```
**Update for `dev`:**
```diff
-"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development",
+"dev": "webpack -w -c ./webpack.config.ts --env development",
```
### Configure grafana image to use when running docker
By default, `grafana-enterprise` will be used as the docker image for all docker related commands. If you want to override this behavior, simply alter the `docker-compose.yaml` by adding the following build arg `grafana_image`.
**Example:**
```yaml
version: '3.7'
services:
grafana:
container_name: 'myorg-basic-app'
build:
context: ./.config
args:
grafana_version: ${GRAFANA_VERSION:-9.1.2}
grafana_image: ${GRAFANA_IMAGE:-grafana}
```
In this example, we assign the environment variable `GRAFANA_IMAGE` to the build arg `grafana_image` with a default value of `grafana`. This will allow you to set the value while running the docker compose commands, which might be convenient in some scenarios.
---
@@ -1,18 +0,0 @@
#!/bin/sh
if [ "${DEV}" = "false" ]; then
echo "Starting test mode"
exec /run.sh
fi
echo "Starting development mode"
if grep -i -q alpine /etc/issue; then
exec /usr/bin/supervisord -c /etc/supervisord.conf
elif grep -i -q ubuntu /etc/issue; then
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
else
echo 'ERROR: Unsupported base image'
exit 1
fi
@@ -1,28 +0,0 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-jest-config
*/
import '@testing-library/jest-dom';
import { TextEncoder, TextDecoder } from 'util';
Object.assign(global, { TextDecoder, TextEncoder });
// https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
Object.defineProperty(global, 'matchMedia', {
writable: true,
value: (query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
}),
});
HTMLCanvasElement.prototype.getContext = () => {};
@@ -1,43 +0,0 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-jest-config
*/
const path = require('path');
const { grafanaESModules, nodeModulesToTransform } = require('./jest/utils');
module.exports = {
moduleNameMapper: {
'\\.(css|scss|sass)$': 'identity-obj-proxy',
'react-inlinesvg': path.resolve(__dirname, 'jest', 'mocks', 'react-inlinesvg.tsx'),
},
modulePaths: ['<rootDir>/src'],
setupFilesAfterEnv: ['<rootDir>/jest-setup.js'],
testEnvironment: 'jest-environment-jsdom',
testMatch: [
'<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',
'<rootDir>/src/**/*.{spec,test,jest}.{js,jsx,ts,tsx}',
'<rootDir>/src/**/*.{spec,test,jest}.{js,jsx,ts,tsx}',
],
transform: {
'^.+\\.(t|j)sx?$': [
'@swc/jest',
{
sourceMaps: 'inline',
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
decorators: false,
dynamicImport: true,
},
},
},
],
},
// Jest will throw `Cannot use import statement outside module` if it tries to load an
// ES module without it being transformed first. ./config/README.md#esm-errors-with-jest
transformIgnorePatterns: [nodeModulesToTransform(grafanaESModules)],
};
@@ -1,25 +0,0 @@
// Due to the grafana/ui Icon component making fetch requests to
// `/public/img/icon/<icon_name>.svg` we need to mock react-inlinesvg to prevent
// the failed fetch requests from displaying errors in console.
import React from 'react';
type Callback = (...args: any[]) => void;
export interface StorageItem {
content: string;
queue: Callback[];
status: string;
}
export const cacheStore: { [key: string]: StorageItem } = Object.create(null);
const SVG_FILE_NAME_REGEX = /(.+)\/(.+)\.svg$/;
const InlineSVG = ({ src }: { src: string }) => {
// testId will be the file name without extension (e.g. `public/img/icons/angle-double-down.svg` -> `angle-double-down`)
const testId = src.replace(SVG_FILE_NAME_REGEX, '$2');
return <svg xmlns="http://www.w3.org/2000/svg" data-testid={testId} viewBox="0 0 24 24" />;
};
export default InlineSVG;
@@ -1,31 +0,0 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in .config/README.md
*/
/*
* This utility function is useful in combination with jest `transformIgnorePatterns` config
* to transform specific packages (e.g.ES modules) in a projects node_modules folder.
*/
const nodeModulesToTransform = (moduleNames) => `node_modules\/(?!.*(${moduleNames.join('|')})\/.*)`;
// Array of known nested grafana package dependencies that only bundle an ESM version
const grafanaESModules = [
'.pnpm', // Support using pnpm symlinked packages
'@grafana/schema',
'd3',
'd3-color',
'd3-force',
'd3-interpolate',
'd3-scale-chromatic',
'ol',
'react-colorful',
'rxjs',
'uuid',
];
module.exports = {
nodeModulesToTransform,
grafanaESModules,
};
@@ -1,47 +0,0 @@
[supervisord]
nodaemon=true
user=root
[program:grafana]
user=root
directory=/var/lib/grafana
command=bash -c 'while [ ! -f /root/timely-datasource/dist/timely_datasource* ]; do sleep 1; done; /run.sh'
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
killasgroup=true
stopasgroup=true
autostart=true
[program:delve]
user=root
command=/bin/bash -c 'pid=""; while [ -z "$pid" ]; do pid=$(pgrep -f timely_datasource); done; /root/go/bin/dlv attach --api-version=2 --headless --continue --accept-multiclient --listen=:2345 $pid'
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
killasgroup=false
stopasgroup=false
autostart=true
autorestart=true
[program:build-watcher]
user=root
command=/bin/bash -c 'while inotifywait -e modify,create,delete -r /var/lib/grafana/plugins/timely-datasource; do echo "Change detected, restarting delve...";supervisorctl restart delve; done'
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
killasgroup=true
stopasgroup=true
autostart=true
[program:mage-watcher]
user=root
environment=PATH="/usr/local/go/bin:/root/go/bin:%(ENV_PATH)s"
directory=/root/timely-datasource
command=/bin/bash -c 'git config --global --add safe.directory /root/timely-datasource && mage -v watch'
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
killasgroup=true
stopasgroup=true
autostart=true
@@ -1,26 +0,0 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-typescript-config
*/
{
"compilerOptions": {
"alwaysStrict": true,
"declaration": false,
"rootDir": "../src",
"baseUrl": "../src",
"typeRoots": ["../node_modules/@types"],
"resolveJsonModule": true
},
"ts-node": {
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"esModuleInterop": true
},
"transpileOnly": true
},
"include": ["../src", "./types"],
"extends": "@grafana/tsconfig"
}
Loaded 100 of 194 files, more files were not shown because too many files have changed in this diff. Show more