mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
Included the following with core changes to allow labeled metrics for Prometheus exposition format publishing. * javadoc updates * remove extra types * use NBLabeledElement instead of NBNamedElement * contextualize NBLabeledElement for graphite/metrics * externalize labeled ScriptContext to API * add labels to NicerTimer * remove partial packaging * more progress on formatting for prom exposition format * added metrics diagram * resolve build issues with label params * resolve build issues with label params * prometheus export services * added PromExpoFormat Tests for NBMetricMeter(Counting+Sampling) and NBMetricTimer(Counting) * added test for Gauge Formatting * added Gauge Formatting as well as Sampling values (count, stdev ...) * added sketch for metrics labeling contexts * add NBLabeledElement in all the places, retool calling paths to use it * synchronize antlr versions after partial snyk change * unbreak static initializer block after IntelliJ "fixed" it. * engine-api - adapt to NBLabeledElement * adapters-api - adapt to NBLabeledElement * nb-api - adapt to NBLabeledElement * engine-core - adapt to NBLabeledElement * misc-adapters - adapt to NBLabeledElement * streaming-adapters - adapt to NBLabeledElement * add missing test * initial implementation of a prom push reporter * Resolve build issue with parseGlobalOptions * replaced with PromPushReporter * cleanup unused deps * dependency removal for micrometer * allow empty labels for tests * change space.getName to space.getSpaceName * cleanup poms * graphite linearization now includes space element * http adapter should only depend on adapters API * http space does not create its own metric names * import cleanups * improved javadocs * introduce component concepts --------- Co-authored-by: Jonathan Shook <jshook@gmail.com> Co-authored-by: Mike Yaacoub <mike.yaacoub@datastax.com>
297 lines
11 KiB
Java
297 lines
11 KiB
Java
/*
|
|
* Copyright (c) 2022-2023 nosqlbench
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package io.nosqlbench.adapter.tcpserver;
|
|
|
|
import io.nosqlbench.api.config.standard.ConfigModel;
|
|
import io.nosqlbench.api.config.standard.NBConfigModel;
|
|
import io.nosqlbench.api.config.standard.NBConfiguration;
|
|
import io.nosqlbench.api.config.standard.Param;
|
|
import io.nosqlbench.api.engine.util.SSLKsFactory;
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
import javax.net.ServerSocketFactory;
|
|
import javax.net.ssl.SSLServerSocketFactory;
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.io.OutputStreamWriter;
|
|
import java.io.Writer;
|
|
import java.net.InetAddress;
|
|
import java.net.ServerSocket;
|
|
import java.net.Socket;
|
|
import java.net.SocketTimeoutException;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.concurrent.BlockingQueue;
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
public class TcpServerAdapterSpace implements AutoCloseable {
|
|
|
|
|
|
private final static Logger logger = LogManager.getLogger(TcpServerAdapterSpace.class);
|
|
private final NBConfiguration config;
|
|
Writer writer;
|
|
private LinkedBlockingQueue<String> queue;
|
|
private ServerSocket listenerSocket;
|
|
private final List<Shutdown> managedShutdown = new ArrayList<>();
|
|
private int capacity=10;
|
|
|
|
public TcpServerAdapterSpace(NBConfiguration config) {
|
|
this.config = config;
|
|
this.writer = createPrintWriter();
|
|
}
|
|
|
|
private Writer createPrintWriter() {
|
|
|
|
boolean sslEnabled = config.getOptional(Boolean.class, "ssl").orElse(false);
|
|
this.capacity=config.getOptional(int.class, "capacity").orElse(10);
|
|
queue = new LinkedBlockingQueue<>(capacity);
|
|
ServerSocketFactory socketFactory;
|
|
if (sslEnabled) {
|
|
|
|
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(config);
|
|
socketFactory = SSLKsFactory.get().createSSLServerSocketFactory(sslCfg);
|
|
} else {
|
|
socketFactory = ServerSocketFactory.getDefault();
|
|
}
|
|
|
|
String host = config.getOptional("host").orElse("localhost");
|
|
int port = config.getOptional(int.class, "port").orElse(12345);
|
|
|
|
if (listenerSocket == null || listenerSocket.isClosed()) {
|
|
try {
|
|
InetAddress hostAddr = InetAddress.getByName(host);
|
|
listenerSocket = socketFactory.createServerSocket(port, 10, hostAddr);
|
|
if (socketFactory instanceof SSLServerSocketFactory) {
|
|
logger.info("SSL enabled on server socket " + listenerSocket);
|
|
}
|
|
SocketAcceptor socketAcceptor = new SocketAcceptor(queue, listenerSocket);
|
|
managedShutdown.add(socketAcceptor);
|
|
Thread acceptorThread = new Thread(socketAcceptor);
|
|
acceptorThread.setDaemon(true);
|
|
acceptorThread.setName("Listener/" + listenerSocket);
|
|
acceptorThread.start();
|
|
} catch (IOException e) {
|
|
throw new RuntimeException("Error listening on listenerSocket:" + e, e);
|
|
}
|
|
}
|
|
|
|
QueueWriterAdapter queueWriterAdapter = new QueueWriterAdapter(this.queue);
|
|
logger.info("initialized queue writer:" + queueWriterAdapter);
|
|
return queueWriterAdapter;
|
|
}
|
|
|
|
@Override
|
|
public void close() throws Exception {
|
|
logger.info("TcpServerAdapterSpace is waiting for message queue to empty");
|
|
while(this.queue != null && !this.queue.isEmpty())
|
|
{
|
|
try {
|
|
Thread.sleep(10);
|
|
}catch (InterruptedException e) {
|
|
}
|
|
}
|
|
logger.info("TcpServerAdapterSpace is being closed");
|
|
for (Shutdown toClose : managedShutdown) {
|
|
toClose.shutdown();
|
|
}
|
|
}
|
|
|
|
public void writeflush(String text) {
|
|
try {
|
|
if(this.writer == null)
|
|
{
|
|
this.writer = createPrintWriter();
|
|
}
|
|
this.writer.write(text);
|
|
this.writer.flush();
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
public static NBConfigModel getConfigModel() {
|
|
return ConfigModel.of(TcpServerAdapterSpace.class)
|
|
.add(SSLKsFactory.get().getConfigModel())
|
|
.add(
|
|
Param.defaultTo("capacity",10)
|
|
.setDescription("the capacity of the queue")
|
|
)
|
|
.add(
|
|
Param.defaultTo("host","localhost")
|
|
.setDescription("the host address to use")
|
|
)
|
|
.add(
|
|
Param.defaultTo("port",12345)
|
|
.setDescription("the designated port to connect to on the socket")
|
|
)
|
|
.add(
|
|
Param.defaultTo("newline",true)
|
|
.setDescription("whether to automatically add a missing newline to the end of any output\n")
|
|
)
|
|
.add(
|
|
Param.optional("format")
|
|
.setRegex("csv|readout|json|inlinejson|assignments|diag")
|
|
.setDescription("""
|
|
Which format to use.
|
|
"If provided, the format will override any statement formats provided by the YAML.
|
|
"If 'diag' is used, a diagnostic readout will be provided for binding constructions.""")
|
|
)
|
|
.add(
|
|
Param.defaultTo("bindings","doc")
|
|
.setDescription("""
|
|
This is a simple way to specify a filter for the names of bindings that you want to use.
|
|
"If this is 'doc', then all the document level bindings are used. If it is any other value, it is taken
|
|
"as a pattern (regex) to subselect a set of bindings by name. You can simply use the name of a binding
|
|
"here as well.""")
|
|
|
|
)
|
|
.asReadOnly();
|
|
}
|
|
private interface Shutdown {
|
|
void shutdown();
|
|
}
|
|
public static class SocketWriter implements Runnable, Shutdown {
|
|
private final BlockingQueue<String> sourceQueue;
|
|
private final Socket connectedSocket;
|
|
private boolean running = true;
|
|
|
|
|
|
public SocketWriter(BlockingQueue<String> sourceQueue, Socket connectedSocket) {
|
|
this.sourceQueue = sourceQueue;
|
|
this.connectedSocket = connectedSocket;
|
|
}
|
|
|
|
public void shutdown() {
|
|
this.running = false;
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
OutputStream outputStream = null;
|
|
try {
|
|
outputStream = connectedSocket.getOutputStream();
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
try (Writer runWriter = new OutputStreamWriter(outputStream)) {
|
|
while (running ) {
|
|
if(!sourceQueue.isEmpty()) {
|
|
try {
|
|
//String data = sourceQueue.take();
|
|
String data = sourceQueue.poll(1, TimeUnit.SECONDS);
|
|
if(data == null) {
|
|
continue;
|
|
}
|
|
runWriter.write(data);
|
|
runWriter.flush();
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
try {
|
|
Thread.sleep(10);
|
|
} catch (InterruptedException ignored) {
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public static class QueueWriterAdapter extends Writer {
|
|
private BlockingQueue<String> queue;
|
|
|
|
private volatile boolean running = true;
|
|
|
|
public QueueWriterAdapter(BlockingQueue<String> queue) {
|
|
this.queue = queue;
|
|
}
|
|
|
|
@Override
|
|
public synchronized void write( char[] cbuf, int off, int len) {
|
|
String message = new String(cbuf, off, len);
|
|
while (running) {
|
|
try {
|
|
if(queue.offer(message, 1, TimeUnit.SECONDS)) {
|
|
return;
|
|
}
|
|
} catch (InterruptedException ignored) {
|
|
logger.debug("QueueWriterAdapter was interrupted");
|
|
running =false;
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized void flush() throws IOException {
|
|
}
|
|
|
|
@Override
|
|
public synchronized void close() throws IOException {
|
|
flush();
|
|
running =false;
|
|
queue = null;
|
|
}
|
|
|
|
}
|
|
|
|
public class SocketAcceptor implements Runnable, Shutdown {
|
|
private final BlockingQueue<String> queue;
|
|
private final ServerSocket serverSocket;
|
|
private boolean running = true;
|
|
|
|
public SocketAcceptor(BlockingQueue<String> queue, ServerSocket serverSocket) {
|
|
this.queue = queue;
|
|
this.serverSocket = serverSocket;
|
|
}
|
|
|
|
public void shutdown() {
|
|
this.running = false;
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
try (ServerSocket runServerSocket = this.serverSocket) {
|
|
while (running) {
|
|
runServerSocket.setSoTimeout(1000);
|
|
runServerSocket.setReuseAddress(true);
|
|
try {
|
|
Socket connectedSocket = runServerSocket.accept();
|
|
SocketWriter writer = new SocketWriter(queue, connectedSocket);
|
|
managedShutdown.add(writer);
|
|
Thread writerThread = new Thread(writer);
|
|
writerThread.setName("SocketWriter/" + connectedSocket);
|
|
writerThread.setDaemon(false);
|
|
writerThread.start();
|
|
logger.info("Started writer thread for " + connectedSocket);
|
|
} catch (SocketTimeoutException e) {
|
|
logger.debug("Socket timeout when waiting for a client connection to SocketWriter Server");
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
}
|
|
}
|