provide a more condensed session identifier for metrics

This commit is contained in:
Jonathan Shook
2023-08-28 16:15:34 -05:00
parent 0812f15ea2
commit aec7301e99
5 changed files with 193 additions and 33 deletions

View File

@@ -69,7 +69,7 @@ public class RawOpDef extends RawOpFields {
Object op = map.remove(keyName);
if (op instanceof CharSequence s) {
if (!keyName.equals("stmt")) {
logger.warn("Used implied stmt field under name '" + keyName + "'. You can just use 'stmt: ... "+ s +"' or the equivalent to avoid this warning.");
logger.info("Used implied stmt field under name '" + keyName + "'. You can just use 'stmt: ... "+ s +"' or the equivalent to avoid this warning.");
}
map.put("stmt",s.toString());
// setOp(new LinkedHashMap<String,Object>(Map.of("stmt",s.toString())));
@@ -79,7 +79,7 @@ public class RawOpDef extends RawOpFields {
}
if (found.size() > 1) {
throw new BasicError("You used " + found + " as an op name, but only one of these is allowed at a time.");
} else if ((getName() == null || getName().isEmpty()) && op == null && map.size() > 0) {
} else if ((getName() == null || getName().isEmpty()) && op == null && !map.isEmpty()) {
Map.Entry<String, Object> first = map.entrySet().iterator().next();
setName(first.getKey());
setOp(first.getValue());
@@ -90,7 +90,7 @@ public class RawOpDef extends RawOpFields {
if (_op) {
if (_params) {
if (map.size() > 0) {
if (!map.isEmpty()) {
throw new OpConfigError("If you have scoped op and params, you may not have dangling fields. Op template named '" + this.getName() + "' is invalid. Move dangling params ("+ map.keySet() +") under another field.");
}
} else { // no params. Op was a scoped field and there are dangling fields, so assume they belong to params

View File

@@ -86,6 +86,8 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
private NBLabels labels;
private String sessionName;
private String sessionCode;
private long sessionTime;
public NBCLI(final String commandName) {
this.commandName = commandName;
@@ -153,10 +155,17 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
// logger = LogManager.getLogger("NBCLI");
NBCLI.loggerConfig.setConsoleLevel(NBLogLevel.ERROR);
this.sessionTime = System.currentTimeMillis();
final NBCLIOptions globalOptions = new NBCLIOptions(args, Mode.ParseGlobalsOnly);
this.labels=NBLabels.forKV("command",commandName).and(globalOptions.getLabelMap());
this.sessionName = SessionNamer.format(globalOptions.getSessionName());
this.sessionCode = SystemId.genSessionCode(sessionTime);
this.sessionName = SessionNamer.format(globalOptions.getSessionName(),sessionTime).replaceAll("SESSIONCODE",sessionCode);
this.labels = NBLabels.forKV("command", commandName, "appname", "nosqlbench")
.andInstances("node",SystemId.getNodeId())
.andInstances("nodeid",SystemId.getPackedNodeId())
// .andInstances("sesscode",sessionCode)
.andInstances("session",sessionName)
.and(globalOptions.getLabelMap());
NBCLI.loggerConfig
.setSessionName(sessionName)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 nosqlbench
* 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.
@@ -23,6 +23,7 @@ import oshi.hardware.CentralProcessor;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.hardware.NetworkIF;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -36,32 +37,37 @@ public class SystemId {
* when you are managing configuration or results for a set of systems which
* share a common IP addressing scheme. This identifier should be stable as long
* as the node's addresses do not change.
*
* If you are needing an identifier for a node but wish to expose any address data,
* <p>
* If you are needing an identifier for a node but do not with wish to expose any address data,
* you can use the {@link #getNodeFingerprint()} which takes this value and hashes
* it with SHA-1 to produce a hex string.
*
* @return A address for the node, likely to be unique and stable for its lifetime
*/
public static String getNodeId() {
return getMainInetAddrDirect().map(InetAddress::getHostAddress).orElse("UNKNOWN_HOST_ID");
}
private static String getNodeIdOSHI() {
SystemInfo sysinfo = new SystemInfo();
HardwareAbstractionLayer hal = sysinfo.getHardware();
List<NetworkIF> interfaces = hal.getNetworkIFs();
Optional<String> first = interfaces.stream()
.filter(i -> !i.getName().startsWith("docker" ))
.filter(i -> !i.getName().equals("lo" ))
.sorted((o1, o2) -> {
if (o1.getName().startsWith("e" ) && o2.getName().startsWith("e" )) {
return 0;
}
if (o1.getName().startsWith("e" )) {
return -1;
}
if (o2.getName().startsWith("e" )) {
return 1;
}
.filter(i -> !i.getName().startsWith("docker"))
.filter(i -> !i.getName().equals("lo"))
.sorted((o1, o2) -> {
if (o1.getName().startsWith("e") && o2.getName().startsWith("e")) {
return 0;
})
}
if (o1.getName().startsWith("e")) {
return -1;
}
if (o2.getName().startsWith("e")) {
return 1;
}
return 0;
})
.flatMap(iface -> Arrays.stream(iface.getIPv4addr().clone()))
.filter(addr -> !(addr.startsWith("127.")))
.findFirst();
@@ -69,10 +75,51 @@ public class SystemId {
return systemID;
}
private static Optional<InetAddress> getMainInetAddrDirect() {
List<NetworkInterface> ifaces = getInterfacesDirect();
Optional<NetworkInterface> first = ifaces.stream()
.filter(i -> !i.getName().startsWith("docker"))
.filter(i -> !i.getName().equals("lo"))
.sorted((o1, o2) -> {
if (o1.getName().startsWith("e") && o2.getName().startsWith("e")) return 0;
if (o1.getName().startsWith("e")) return -1;
if (o2.getName().startsWith("e")) return 1;
return 0;
}).findFirst();
if (first.isEmpty()) return Optional.empty();
Optional<InetAddress> firstInetAddrForInterface = first.get().getInterfaceAddresses().stream()
.map(ia -> ia.getAddress())
.sorted((i1, i2) -> {
if (i1 instanceof Inet4Address && i2 instanceof Inet4Address) return 0;
if (i1 instanceof Inet4Address) return -1;
if (i2 instanceof Inet4Address) return 1;
return 0;
}).findFirst();
return firstInetAddrForInterface;
}
/**
* Using this to bypass OSHI because it calls logger init before we want it.
* TODO: Maybe remove OSHI altogether if there is a reasonable Java HAL view in current Java editions.
*
* @return a list of network interfaces
*/
private static List<NetworkInterface> getInterfacesDirect() {
try {
Enumeration<NetworkInterface> ni = NetworkInterface.getNetworkInterfaces();
return new ArrayList<>(Collections.list(ni));
} catch (SocketException e) {
throw new RuntimeException(e);
}
}
/**
* Produce a stable string identifier consisting of hexadecimal characters.
* The internal data used for this value is based on a stable ordering of non-local
* ip addresses available on the system.
*
* @return A stable node identifier
*/
public static String getNodeFingerprint() {
@@ -81,9 +128,9 @@ public class SystemId {
MessageDigest sha1_digest = MessageDigest.getInstance("SHA-1");
byte[] addrBytes = sha1_digest.digest(addrId.getBytes(StandardCharsets.UTF_8));
String fingerprint = "";
for (int i=0; i < addrBytes.length; i++) {
for (int i = 0; i < addrBytes.length; i++) {
fingerprint +=
Integer.toString( ( addrBytes[i] & 0xff ) + 0x100, 16).substring( 1 );
Integer.toString((addrBytes[i] & 0xff) + 0x100, 16).substring(1);
}
return fingerprint.toUpperCase(Locale.ROOT);
} catch (NoSuchAlgorithmException e) {
@@ -125,4 +172,75 @@ public class SystemId {
return gson.toJson(details);
}
private final static String radixSymbols = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~-"; // 64 symbols, for 2^6!
private final int brailleStart = '';
private final int brailleEnd = '⣿';
private final int brailleRadix = brailleEnd - brailleStart;
public static String getBrailleNodeId() {
String nodeId = getNodeId();
String[] fields = nodeId.split("\\.");
byte[] addr;
try {
InetAddress inetAddr = Inet4Address.getByName(nodeId);
addr = inetAddr.getAddress();
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
return braille((addr[0] << 24) + (addr[1] << 16) + (addr[2] << 8) + addr[3]);
}
private static String braille(int value) {
StringBuilder buf = new StringBuilder(4);
for (int i = 0; i < 4; i++) {
int mask = value & 0xF;
value >>= 8;
int charat = '' + mask;
buf.append((char) charat);
}
return buf.toString();
}
private static String braille(long value) {
StringBuilder buf = new StringBuilder(8);
for (int i = 0; i < 8; i++) {
int mask = (int) value & 0xF;
value >>= 8;
int charat = '' + mask;
buf.append((char) charat);
}
return buf.toString();
}
public static String genSessionCode(long epochMillis) {
return pack(epochMillis) + "_" + getPackedNodeId();
}
public static String getPackedNodeId() {
String nodeId = getNodeId();
String[] fields = nodeId.split("\\.");
byte[] addr;
try {
InetAddress inetAddr = Inet4Address.getByName(nodeId);
addr = inetAddr.getAddress();
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
return pack((addr[0] << 24) + (addr[1] << 16) + (addr[2] << 8) + addr[3]);
}
public static String pack(long bitfield) {
StringBuilder sb = new StringBuilder(11);
while (bitfield > 0) {
long tail = bitfield & 0b00111111;
bitfield >>= 6;
sb.append(radixSymbols.charAt((int) tail));
}
return sb.toString();
}
public static String genSessionBits() {
return getBrailleNodeId() + ":" + braille(System.currentTimeMillis());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 nosqlbench
* 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.
@@ -17,28 +17,61 @@
package io.nosqlbench.nb.api;
import io.nosqlbench.api.metadata.SystemId;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class SystemIdTest {
private static final Logger logger = LogManager.getLogger(SystemIdTest.class);
@Test
public void testHostInfo() {
String info = SystemId.getHostSummary();
System.out.println(info);
String hostSummary = SystemId.getHostSummary();
logger.info("host summary: " + hostSummary);
}
@Test
public void testNostId() {
String info = SystemId.getNodeId();
assertThat(info).matches("\\d+\\.\\d+\\.\\d+\\.\\d+");
String nodeId = SystemId.getNodeId();
assertThat(nodeId).matches("\\d+\\.\\d+\\.\\d+\\.\\d+");
logger.info("node id: " + nodeId);
}
@Test
public void testNodeFingerprint() {
String hash = SystemId.getNodeFingerprint();
assertThat(hash).matches("[A-Z0-9]+");
String nodeFingerprint = SystemId.getNodeFingerprint();
assertThat(nodeFingerprint).matches("[A-Z0-9]+");
logger.info("node fingerprint: " + nodeFingerprint);
}
@Test
public void testBrailleNodeId() {
String brailleNodeId = SystemId.getBrailleNodeId();
assertThat(brailleNodeId).matches("[-⣿]{4}"); // note, that is not a space. It is the starting braille value of empty
logger.info("braille node id: " + brailleNodeId);
}
@Test
public void testPackedNodeId() {
String packedNodeId = SystemId.getPackedNodeId();
assertThat(packedNodeId).matches("[0-9A-Za-z_-]+");
logger.info("packed node id: " + packedNodeId);
}
@Test
public void testGenSessionCode() {
String sessionCode=SystemId.genSessionCode(234L);
assertThat(sessionCode).matches("[0-9a-zA-Z~-]+_[0-9a-zA-Z~-]+");
logger.info("session code: " + sessionCode);
}
@Test
public void testGenSessionBits() {
String sessionBits = SystemId.genSessionBits();
assertThat(sessionBits).matches("[-⣿]+:[-⣿]+");
logger.info("session bits: " + sessionBits);
}
}

View File

@@ -61,7 +61,7 @@
<module.adapter-tcp>adapter-tcp</module.adapter-tcp>
<module.adapter-dynamodb>adapter-dynamodb</module.adapter-dynamodb>
<module.adapter-mongodb>adapter-mongodb</module.adapter-mongodb>
<module.adapter-venice>adapter-venice</module.adapter-venice>
<!-- <module.adapter-venice>adapter-venice</module.adapter-venice>-->
<module.adapter-pulsar>adapter-pulsar</module.adapter-pulsar>
<module.adapter-s4j>adapter-s4j</module.adapter-s4j>
<module.adapter-kafka>adapter-kafka</module.adapter-kafka>
@@ -102,7 +102,7 @@
<module>adapters-api</module>
<!-- driver modules -->
<module>adapter-venice</module>
<!-- <module>adapter-venice</module>-->
<module>adapter-diag</module>
<module>adapter-stdout</module>
<module>adapter-cqld4</module>