Merge pull request #1485 from nosqlbench/nosqlbench-1467

Nosqlbench vector fixes
This commit is contained in:
Jonathan Shook 2023-08-28 18:45:41 -05:00 committed by GitHub
commit 6cee58aadb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 1073 additions and 605 deletions

View File

@ -51,7 +51,7 @@ public class AmqpAdapterMetrics {
public AmqpAdapterMetrics(final AmqpBaseOpDispenser amqpBaseOpDispenser, final NBLabeledElement labeledParent) {
this.amqpBaseOpDispenser = amqpBaseOpDispenser;
labels=labeledParent.getLabels().and("name", AmqpAdapterMetrics.class.getSimpleName());
labels=labeledParent.getLabels().andTypes("name", AmqpAdapterMetrics.class.getSimpleName());
}
public void initS4JAdapterInstrumentation() {

View File

@ -71,13 +71,13 @@ public class NamingFolio {
* by name, type, table, keyspace. For now it just returns everything in fully qualified form.
*/
public String nameFor(NBLabeledElement labeled, String... fields) {
NBLabels labelsPlus = labeled.getLabels().and(fields);
NBLabels labelsPlus = labeled.getLabels().andTypes(fields);
String name = namer.apply(labelsPlus.asMap());
return name;
}
public String nameFor(NBLabeledElement labeled, Map<String,String> fields) {
NBLabels labelsPlus = labeled.getLabels().and(fields);
NBLabels labelsPlus = labeled.getLabels().andTypes(fields);
String name = namer.apply(labelsPlus.asMap());
return name;

View File

@ -42,6 +42,6 @@ public class CqlTableColumn extends CqlColumnBase {
@Override
public NBLabels getLabels() {
return super.getLabels().and("table", table.getName());
return super.getLabels().andTypes("table", table.getName());
}
}

View File

@ -42,6 +42,6 @@ public class CqlTypeColumn extends CqlColumnBase {
@Override
public NBLabels getLabels() {
return super.getLabels().and("name", this.type.getName());
return super.getLabels().andTypes("name", this.type.getName());
}
}

View File

@ -171,6 +171,6 @@ public class DiagTask_gauge extends BaseDiagTask implements Gauge<Double> {
@Override
public NBLabels getLabels() {
return super.getLabels().and("stat",this.stat.toString());
return super.getLabels().andTypes("stat",this.stat.toString());
}
}

View File

@ -51,7 +51,7 @@ public class KafkaAdapterMetrics {
public KafkaAdapterMetrics(final KafkaBaseOpDispenser kafkaBaseOpDispenser, final NBLabeledElement labeledParent) {
this.kafkaBaseOpDispenser = kafkaBaseOpDispenser;
labels=labeledParent.getLabels().and("name",KafkaAdapterMetrics.class.getSimpleName());
labels=labeledParent.getLabels().andTypes("name",KafkaAdapterMetrics.class.getSimpleName());
}
public void initS4JAdapterInstrumentation() {

View File

@ -114,7 +114,8 @@ public class OpsLoader {
stderrStream,
new os.Path(Path.of(System.getProperty("user.dir"))),
Option.empty(),
Option.empty()
Option.empty(),
null
);
String stdoutOutput = stdoutBuffer.toString(StandardCharsets.UTF_8);

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

@ -154,6 +154,7 @@ public abstract class BaseDriverAdapter<R extends Op, S> implements DriverAdapte
public NBConfigModel getConfigModel() {
return ConfigModel.of(BaseDriverAdapter.class)
.add(Param.optional("alias"))
.add(Param.optional("labels",String.class,"Labels which will apply to metrics and annotations for this activity only"))
.add(Param.defaultTo("strict", true, "strict op field mode, which requires that provided op fields are recognized and used"))
.add(Param.optional(List.of("op", "stmt", "statement"), String.class, "op template in statement form"))
.add(Param.optional("tags", String.class, "tags to be used to filter operations"))

View File

@ -17,6 +17,7 @@
package io.nosqlbench.adapters.api.templating;
import io.nosqlbench.adapters.api.activityconfig.yaml.OpTemplate;
import io.nosqlbench.api.config.NBLabelSpec;
import io.nosqlbench.api.config.NBLabeledElement;
import io.nosqlbench.api.config.NBLabels;
import io.nosqlbench.api.config.fieldreaders.DynamicFieldReader;
@ -328,19 +329,19 @@ public class ParsedOp implements LongFunction<Map<String, ?>>, NBLabeledElement,
* The activity configuration, used to resolve nested config parameters
* @param preprocessors
* Map->Map transformers.
* @param labels
*/
public ParsedOp(
OpTemplate opTemplate,
NBConfiguration activityCfg,
List<Function<Map<String, Object>, Map<String, Object>>> preprocessors,
NBLabeledElement parent) {
NBLabeledElement parent
) {
this._opTemplate = opTemplate;
this.activityCfg = activityCfg;
labels=parent.getLabels().and("op", this.getName());
Map<String, Object> map = opTemplate.getOp().orElseThrow(() ->
new OpConfigError("ParsedOp constructor requires a non-null value for the op field, but it was missing."));
for (Function<Map<String, Object>, Map<String, Object>> preprocessor : preprocessors) {
map = preprocessor.apply(map);
}
@ -353,6 +354,19 @@ public class ParsedOp implements LongFunction<Map<String, ?>>, NBLabeledElement,
activityCfg.getMap())
);
NBLabels opLabels = parent.getLabels().andTypes("op", this.getName());
if (tmap.isStatic("labels")) {
Object labelSpecObject = tmap.takeStaticValue("labels", Object.class);
if (labelSpecObject instanceof String labelsSpec) {
NBLabels op_specific_labels = NBLabelSpec.parseLabels(labelsSpec);
opLabels=opLabels.and(op_specific_labels);
} else {
throw new OpConfigError("parsing labels as type '" + labelSpecObject.getClass().getSimpleName() +"' is not supported.");
}
} else if (tmap.isDynamic("labels")) {
throw new OpConfigError("Labels may not be dynamic.");
}
this.labels=opLabels;
}

View File

@ -27,9 +27,9 @@ public class CoreActivityInstrumentation implements ActivityInstrumentation {
private static final String STRICTMETRICNAMES = "strictmetricnames";
private static final String WAIT_TIME = ".waittime";
private static final String SERVICE_TIME = ".servicetime";
private static final String RESPONSE_TIME = ".responsetime";
private static final String WAIT_TIME = "_waittime";
private static final String SERVICE_TIME = "_servicetime";
private static final String RESPONSE_TIME = "_responsetime";
private final Activity activity;
private final ActivityDef def;
@ -106,7 +106,7 @@ public class CoreActivityInstrumentation implements ActivityInstrumentation {
@Override
public synchronized Timer getOrCreateResultSuccessTimer() {
return ActivityMetrics.timer(this.activity,"result-success", this.activity.getHdrDigits());
return ActivityMetrics.timer(this.activity,"result_success", this.activity.getHdrDigits());
}
@Override

View File

@ -152,9 +152,9 @@ public class HybridRateLimiter implements RateLimiter {
protected void init(final NBLabeledElement activityDef) {
delayGauge = ActivityMetrics.gauge(activityDef, this.label + ".waittime", new RateLimiters.WaitTimeGauge(this));
avgRateGauge = ActivityMetrics.gauge(activityDef, this.label + ".config.cyclerate", new RateLimiters.RateGauge(this));
burstRateGauge = ActivityMetrics.gauge(activityDef, this.label + ".config.burstrate", new RateLimiters.BurstRateGauge(this));
delayGauge = ActivityMetrics.gauge(activityDef, this.label + "_waittime", new RateLimiters.WaitTimeGauge(this));
avgRateGauge = ActivityMetrics.gauge(activityDef, this.label + "_config_cyclerate", new RateLimiters.RateGauge(this));
burstRateGauge = ActivityMetrics.gauge(activityDef, this.label + "_config_burstrate", new RateLimiters.BurstRateGauge(this));
}
@Override

View File

@ -17,6 +17,7 @@
package io.nosqlbench.engine.api.activityimpl;
import com.codahale.metrics.Timer;
import io.nosqlbench.api.config.NBLabelSpec;
import io.nosqlbench.engine.api.activityapi.core.*;
import io.nosqlbench.engine.api.activityapi.core.progress.ActivityMetricProgressMeter;
import io.nosqlbench.engine.api.activityapi.core.progress.ProgressMeterDisplay;
@ -93,27 +94,33 @@ public class SimpleActivity implements Activity {
private final NBLabels labels;
public SimpleActivity(ActivityDef activityDef, NBLabeledElement parentLabels) {
labels = parentLabels.getLabels().and("activity",activityDef.getAlias());
NBLabels activityLabels = parentLabels.getLabels()
.andTypes("activity", activityDef.getAlias());
Optional<String> auxLabelSpec = activityDef.getParams().getOptionalString("labels");
if (auxLabelSpec.isPresent()) {
activityLabels = activityLabels.and(NBLabelSpec.parseLabels(auxLabelSpec.get()));
}
this.labels = activityLabels;
this.activityDef = activityDef;
this.parentLabels = parentLabels;
if (activityDef.getAlias().equals(ActivityDef.DEFAULT_ALIAS)) {
Optional<String> workloadOpt = activityDef.getParams().getOptionalString(
"workload",
"yaml"
"workload",
"yaml"
);
if (workloadOpt.isPresent()) {
activityDef.getParams().set("alias", workloadOpt.get());
} else {
activityDef.getParams().set("alias",
activityDef.getActivityType().toUpperCase(Locale.ROOT)
+ nameEnumerator);
activityDef.getActivityType().toUpperCase(Locale.ROOT)
+ nameEnumerator);
nameEnumerator++;
}
}
}
public SimpleActivity(String activityDefString, NBLabeledElement parentLabels) {
this(ActivityDef.parseActivityDef(activityDefString),parentLabels);
this(ActivityDef.parseActivityDef(activityDefString), parentLabels);
}
@Override
@ -124,8 +131,8 @@ public class SimpleActivity implements Activity {
public synchronized NBErrorHandler getErrorHandler() {
if (null == this.errorHandler) {
errorHandler = new NBErrorHandler(
() -> activityDef.getParams().getOptionalString("errors").orElse("stop"),
() -> getExceptionMetrics());
() -> activityDef.getParams().getOptionalString("errors").orElse("stop"),
() -> getExceptionMetrics());
}
return errorHandler;
}
@ -324,12 +331,12 @@ public class SimpleActivity implements Activity {
public synchronized void initOrUpdateRateLimiters(ActivityDef activityDef) {
activityDef.getParams().getOptionalNamedParameter("striderate")
.map(RateSpec::new)
.ifPresent(spec -> strideLimiter = RateLimiters.createOrUpdate(this, "strides", strideLimiter, spec));
.map(RateSpec::new)
.ifPresent(spec -> strideLimiter = RateLimiters.createOrUpdate(this, "strides", strideLimiter, spec));
activityDef.getParams().getOptionalNamedParameter("cyclerate", "targetrate", "rate")
.map(RateSpec::new).ifPresent(
spec -> cycleLimiter = RateLimiters.createOrUpdate(this, "cycles", cycleLimiter, spec));
.map(RateSpec::new).ifPresent(
spec -> cycleLimiter = RateLimiters.createOrUpdate(this, "cycles", cycleLimiter, spec));
}
@ -338,7 +345,8 @@ public class SimpleActivity implements Activity {
* length of the sequence as determined by the provided ratios. Also, modify the ActivityDef with reasonable
* defaults when requested.
*
* @param seq - The {@link OpSequence} to derive the defaults from
* @param seq
* - The {@link OpSequence} to derive the defaults from
*/
public synchronized void setDefaultsFromOpSequence(OpSequence<?> seq) {
Optional<String> strideOpt = getParams().getOptionalString("stride");
@ -358,15 +366,15 @@ public class SimpleActivity implements Activity {
} else {
if (0 == activityDef.getCycleCount()) {
throw new RuntimeException(
"You specified cycles, but the range specified means zero cycles: " + getParams().get("cycles")
"You specified cycles, but the range specified means zero cycles: " + getParams().get("cycles")
);
}
long stride = getParams().getOptionalLong("stride").orElseThrow();
long cycles = this.activityDef.getCycleCount();
if (cycles < stride) {
throw new RuntimeException(
"The specified cycles (" + cycles + ") are less than the stride (" + stride + "). This means there aren't enough cycles to cause a stride to be executed." +
" If this was intended, then set stride low enough to allow it."
"The specified cycles (" + cycles + ") are less than the stride (" + stride + "). This means there aren't enough cycles to cause a stride to be executed." +
" If this was intended, then set stride low enough to allow it."
);
}
}
@ -376,7 +384,7 @@ public class SimpleActivity implements Activity {
if (0 < stride && 0 != cycleCount % stride) {
logger.warn(() -> "The stride does not evenly divide cycles. Only full strides will be executed," +
"leaving some cycles unused. (stride=" + stride + ", cycles=" + cycleCount + ')');
"leaving some cycles unused. (stride=" + stride + ", cycles=" + cycleCount + ')');
}
Optional<String> threadSpec = activityDef.getParams().getOptionalString("threads");
@ -407,15 +415,15 @@ public class SimpleActivity implements Activity {
if (activityDef.getThreads() > activityDef.getCycleCount()) {
logger.warn(() -> "threads=" + activityDef.getThreads() + " and cycles=" + activityDef.getCycleSummary()
+ ", you should have more cycles than threads.");
+ ", you should have more cycles than threads.");
}
} else if (1000 < cycleCount) {
logger.warn(() -> "For testing at scale, it is highly recommended that you " +
"set threads to a value higher than the default of 1." +
" hint: you can use threads=auto for reasonable default, or" +
" consult the topic on threads with `help threads` for" +
" more information.");
"set threads to a value higher than the default of 1." +
" hint: you can use threads=auto for reasonable default, or" +
" consult the topic on threads with `help threads` for" +
" more information.");
}
if (0 < this.activityDef.getCycleCount() && 0 == seq.getOps().size()) {
@ -426,11 +434,11 @@ public class SimpleActivity implements Activity {
/**
* Given a function that can create an op of type <O> from a CommandTemplate, generate
* an indexed sequence of ready to call operations.
*
* <p>
* This method works almost exactly like the ,
* except that it uses the {@link CommandTemplate} semantics, which are more general and allow
* for map-based specification of operations with bindings in each field.
*
* <p>
* It is recommended to use the CommandTemplate form
* than the
*
@ -440,8 +448,8 @@ public class SimpleActivity implements Activity {
* @return
*/
protected <O extends Op> OpSequence<OpDispenser<? extends O>> createOpSequenceFromCommands(
Function<CommandTemplate, OpDispenser<O>> opinit,
boolean strict
Function<CommandTemplate, OpDispenser<O>> opinit,
boolean strict
) {
Function<OpTemplate, CommandTemplate> f = CommandTemplate::new;
Function<OpTemplate, OpDispenser<? extends O>> opTemplateOFunction = f.andThen(opinit);
@ -450,10 +458,10 @@ public class SimpleActivity implements Activity {
}
protected <O extends Op> OpSequence<OpDispenser<? extends O>> createOpSourceFromParsedOps(
Map<String, DriverAdapter> adapterCache,
Map<String, OpMapper<Op>> mapperCache,
List<DriverAdapter> adapters,
List<ParsedOp> pops
Map<String, DriverAdapter> adapterCache,
Map<String, OpMapper<Op>> mapperCache,
List<DriverAdapter> adapters,
List<ParsedOp> pops
) {
try {
@ -466,9 +474,9 @@ public class SimpleActivity implements Activity {
}
SequencerType sequencerType = getParams()
.getOptionalString("seq")
.map(SequencerType::valueOf)
.orElse(SequencerType.bucket);
.getOptionalString("seq")
.map(SequencerType::valueOf)
.orElse(SequencerType.bucket);
SequencePlanner<OpDispenser<? extends O>> planner = new SequencePlanner<>(sequencerType);
int dryrunCount = 0;
@ -512,10 +520,10 @@ public class SimpleActivity implements Activity {
protected <O extends Op> OpSequence<OpDispenser<? extends O>> createOpSourceFromCommands(
Function<ParsedOp, OpDispenser<? extends O>> opinit,
NBConfiguration cfg,
List<Function<Map<String, Object>, Map<String, Object>>> parsers,
boolean strict
Function<ParsedOp, OpDispenser<? extends O>> opinit,
NBConfiguration cfg,
List<Function<Map<String, Object>, Map<String, Object>>> parsers,
boolean strict
) {
Function<OpTemplate, ParsedOp> f = t -> new ParsedOp(t, cfg, parsers, this);
Function<OpTemplate, OpDispenser<? extends O>> opTemplateOFunction = f.andThen(opinit);
@ -525,7 +533,7 @@ public class SimpleActivity implements Activity {
protected List<ParsedOp> loadParsedOps(NBConfiguration cfg, Optional<DriverAdapter> defaultAdapter) {
List<ParsedOp> parsedOps = loadOpTemplates(defaultAdapter).stream().map(
ot -> new ParsedOp(ot, cfg, List.of(), this)
ot -> new ParsedOp(ot, cfg, List.of(), this)
).toList();
return parsedOps;
}
@ -546,21 +554,21 @@ public class SimpleActivity implements Activity {
// There were no ops, and it was because they were all filtered out
if (0 < unfilteredOps.size()) {
throw new BasicError("There were no active op templates with tag filter '"
+ tagfilter + "', since all " + unfilteredOps.size() + " were filtered out.");
+ tagfilter + "', since all " + unfilteredOps.size() + " were filtered out.");
}
if (defaultDriverAdapter.isPresent() && defaultDriverAdapter.get() instanceof SyntheticOpTemplateProvider sotp) {
filteredOps = sotp.getSyntheticOpTemplates(opsDocList, this.activityDef.getParams());
Objects.requireNonNull(filteredOps);
if (0 == filteredOps.size()) {
throw new BasicError("Attempted to create synthetic ops from driver '" + defaultDriverAdapter.get().getAdapterName() + '\'' +
" but no ops were created. You must provide either a workload or an op parameter. Activities require op templates.");
" but no ops were created. You must provide either a workload or an op parameter. Activities require op templates.");
}
} else {
throw new BasicError("""
No op templates were provided. You must provide one of these activity parameters:
1) workload=some.yaml
2) op='inline template'
3) driver=stdout (or any other drive that can synthesize ops)""");
No op templates were provided. You must provide one of these activity parameters:
1) workload=some.yaml
2) op='inline template'
3) driver=stdout (or any other drive that can synthesize ops)""");
}
if (0 == filteredOps.size()) {
throw new BasicError("There were no active op templates with tag filter '" + tagfilter + '\'');
@ -569,19 +577,19 @@ public class SimpleActivity implements Activity {
if (0 == filteredOps.size()) {
throw new OpConfigError("No op templates found. You must provide either workload=... or op=..., or use " +
"a default driver (driver=___). This includes " +
ServiceLoader.load(DriverAdapter.class).stream()
.filter(p -> {
AnnotatedType[] annotatedInterfaces = p.type().getAnnotatedInterfaces();
for (AnnotatedType ai : annotatedInterfaces) {
if (ai.getType().equals(SyntheticOpTemplateProvider.class)) {
return true;
}
}
return false;
})
.map(d -> d.get().getAdapterName())
.collect(Collectors.joining(",")));
"a default driver (driver=___). This includes " +
ServiceLoader.load(DriverAdapter.class).stream()
.filter(p -> {
AnnotatedType[] annotatedInterfaces = p.type().getAnnotatedInterfaces();
for (AnnotatedType ai : annotatedInterfaces) {
if (ai.getType().equals(SyntheticOpTemplateProvider.class)) {
return true;
}
}
return false;
})
.map(d -> d.get().getAdapterName())
.collect(Collectors.joining(",")));
}
return filteredOps;
@ -590,7 +598,7 @@ public class SimpleActivity implements Activity {
/**
* Given a function that can create an op of type <O> from an OpTemplate, generate
* an indexed sequence of ready to call operations.
*
* <p>
* This method uses the following conventions to derive the sequence:
*
* <OL>
@ -604,9 +612,11 @@ public class SimpleActivity implements Activity {
* where the sequence length is the sum of the ratios.</LI>
* </OL>
*
* @param <O> A holder for an executable operation for the native driver used by this activity.
* @param opinit A function to map an OpTemplate to the executable operation form required by
* the native driver for this activity.
* @param <O>
* A holder for an executable operation for the native driver used by this activity.
* @param opinit
* A function to map an OpTemplate to the executable operation form required by
* the native driver for this activity.
* @param defaultAdapter
* @return The sequence of operations as determined by filtering and ratios
*/
@ -624,9 +634,9 @@ public class SimpleActivity implements Activity {
}
SequencerType sequencerType = getParams()
.getOptionalString("seq")
.map(SequencerType::valueOf)
.orElse(SequencerType.bucket);
.getOptionalString("seq")
.map(SequencerType::valueOf)
.orElse(SequencerType.bucket);
SequencePlanner<OpDispenser<? extends O>> planner = new SequencePlanner<>(sequencerType);
try {
@ -654,7 +664,7 @@ public class SimpleActivity implements Activity {
if (stmt.isPresent()) {
String op = stmt.get();
workloadSource = "commandline:" + stmt.get();
if (op.startsWith("{")||op.startsWith("[")) {
if (op.startsWith("{") || op.startsWith("[")) {
return OpsLoader.loadString(stmt.get(), OpTemplateFormat.json, activityDef.getParams(), null);
} else {
return OpsLoader.loadString(stmt.get(), OpTemplateFormat.inline, activityDef.getParams(), null);
@ -670,7 +680,6 @@ public class SimpleActivity implements Activity {
} catch (Exception e) {
throw new OpConfigError("Error loading op templates: " + e, workloadSource, e);
}
}
@Override

View File

@ -16,7 +16,15 @@
package io.nosqlbench.engine.api.activityimpl.uniform;
import io.nosqlbench.adapters.api.activityconfig.OpsLoader;
import io.nosqlbench.adapters.api.activityconfig.yaml.OpTemplate;
import io.nosqlbench.adapters.api.activityconfig.yaml.OpsDocList;
import io.nosqlbench.adapters.api.activityimpl.OpDispenser;
import io.nosqlbench.adapters.api.activityimpl.OpMapper;
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.adapters.api.activityimpl.uniform.decorators.SyntheticOpTemplateProvider;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import io.nosqlbench.api.Shutdownable;
import io.nosqlbench.api.config.NBLabeledElement;
import io.nosqlbench.api.config.NBLabels;
@ -25,15 +33,7 @@ import io.nosqlbench.api.engine.activityimpl.ActivityDef;
import io.nosqlbench.api.errors.BasicError;
import io.nosqlbench.api.errors.OpConfigError;
import io.nosqlbench.engine.api.activityapi.planning.OpSequence;
import io.nosqlbench.adapters.api.activityconfig.OpsLoader;
import io.nosqlbench.adapters.api.activityconfig.yaml.OpTemplate;
import io.nosqlbench.adapters.api.activityconfig.yaml.OpsDocList;
import io.nosqlbench.adapters.api.activityimpl.OpDispenser;
import io.nosqlbench.adapters.api.activityimpl.OpMapper;
import io.nosqlbench.engine.api.activityimpl.SimpleActivity;
import io.nosqlbench.adapters.api.activityimpl.uniform.decorators.SyntheticOpTemplateProvider;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import io.nosqlbench.nb.annotations.ServiceSelector;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -152,6 +152,7 @@ public class StandardActivity<R extends Op, S> extends SimpleActivity implements
setDefaultsFromOpSequence(sequence);
}
public OpSequence<OpDispenser<? extends Op>> getOpSequence() {
return sequence;
}

View File

@ -91,7 +91,7 @@ public class StandardAction<A extends StandardActivity<R, ?>, R extends Op> impl
while (op != null) {
int tries = 0;
while (tries++ < maxTries) {
while (++tries < maxTries) {
Throwable error = null;
long startedAt = System.nanoTime();

View File

@ -46,7 +46,7 @@ public class NBCLIScenarioParser {
private final static Logger logger = LogManager.getLogger("SCENARIOS");
private static final String SEARCH_IN = "activities";
public static final String WORKLOAD_SCENARIO_STEP = "WORKLOAD_SCENARIO_STEP";
public static final String WORKLOAD_SCENARIO_STEP = "STEP";
public static boolean isFoundWorkload(String workload, String... includes) {
Optional<Content<?>> found = NBIO.all()
@ -190,8 +190,9 @@ public class NBCLIScenarioParser {
buildingCmd.put("alias", "alias=" + WORKLOAD_SCENARIO_STEP);
}
// TODO: simplify this
String alias = buildingCmd.get("alias");
for (String token : new String[]{"WORKLOAD", "SCENARIO", "STEP"}) {
for (String token : new String[]{"STEP"}) {
if (!alias.contains(token)) {
logger.warn("Your alias template '" + alias + "' does not contain " + token + ", which will " +
"cause your metrics to be combined under the same name. It is strongly advised that you " +
@ -206,6 +207,7 @@ public class NBCLIScenarioParser {
alias = alias.replaceAll("STEP", sanitize(stepName));
alias = (alias.startsWith("alias=") ? alias : "alias=" + alias);
buildingCmd.put("alias", alias);
buildingCmd.put("labels","labels=workload:"+sanitize(workloadToken));
logger.debug(() -> "rebuilt command: " + String.join(" ", buildingCmd.values()));
buildCmdBuffer.addAll(buildingCmd.values());
@ -219,7 +221,12 @@ public class NBCLIScenarioParser {
public static String sanitize(String word) {
String sanitized = word;
sanitized = sanitized.replaceAll("\\..+$", "");
sanitized = sanitized.replaceAll("[^a-zA-Z0-9]+", "");
sanitized = sanitized.replaceAll("-","_");
sanitized = sanitized.replaceAll("[^a-zA-Z0-9_]+", "");
if (!word.equals(sanitized)) {
logger.warn("The identifier or value '" + word + "' was sanitized to '" + sanitized + "' to be compatible with monitoring systems. You should probably change this to make diagnostics easier.");
}
return sanitized;
}
@ -326,7 +333,7 @@ public class NBCLIScenarioParser {
OpsDocList stmts = null;
try {
stmts = OpsLoader.loadContent(content, Map.of());
stmts = OpsLoader.loadContent(content, new LinkedHashMap<>());
if (stmts.getStmtDocs().size() == 0) {
logger.warn("Encountered yaml with no docs in '" + referenced + "'");
continue;

View File

@ -16,6 +16,8 @@
package io.nosqlbench.engine.cli;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.nosqlbench.api.annotations.Annotation;
import io.nosqlbench.api.annotations.Layer;
import io.nosqlbench.api.config.NBLabeledElement;
@ -84,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;
@ -95,7 +99,7 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
* for scenario encapsulation and concurrent testing.
*
* @param args
* Command Line Args
* Command Line Args
*/
public static void main(final String[] args) {
try {
@ -151,23 +155,30 @@ 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)
.setConsoleLevel(globalOptions.getConsoleLogLevel())
.setConsolePattern(globalOptions.getConsoleLoggingPattern())
.setLogfileLevel(globalOptions.getScenarioLogLevel())
.setLogfilePattern(globalOptions.getLogfileLoggingPattern())
.setLoggerLevelOverrides(globalOptions.getLogLevelOverrides())
.setMaxLogs(globalOptions.getLogsMax())
.setLogsDirectory(globalOptions.getLogsDirectory())
.setAnsiEnabled(globalOptions.isEnableAnsi())
.setDedicatedVerificationLogger(globalOptions.isDedicatedVerificationLogger())
.activate();
.setSessionName(sessionName)
.setConsoleLevel(globalOptions.getConsoleLogLevel())
.setConsolePattern(globalOptions.getConsoleLoggingPattern())
.setLogfileLevel(globalOptions.getScenarioLogLevel())
.setLogfilePattern(globalOptions.getLogfileLoggingPattern())
.setLoggerLevelOverrides(globalOptions.getLogLevelOverrides())
.setMaxLogs(globalOptions.getLogsMax())
.setLogsDirectory(globalOptions.getLogsDirectory())
.setAnsiEnabled(globalOptions.isEnableAnsi())
.setDedicatedVerificationLogger(globalOptions.isDedicatedVerificationLogger())
.activate();
ConfigurationFactory.setConfigurationFactory(NBCLI.loggerConfig);
NBCLI.logger = LogManager.getLogger("NBCLI");
@ -210,17 +221,16 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
final String reportPromPushTo = globalOptions.wantsReportPromPushTo();
final int mOpts = (dockerMetrics ? 1 : 0)
+ ((null != dockerMetricsAt) ? 1 : 0)
+ ((null != reportGraphiteTo) ? 1 : 0);
+ ((null != dockerMetricsAt) ? 1 : 0)
+ ((null != reportGraphiteTo) ? 1 : 0);
if ((1 < mOpts) && ((null == reportGraphiteTo) || (null == annotatorsConfig)))
throw new BasicError("You have multiple conflicting options which attempt to set\n" +
" the destination for metrics and annotations. Please select only one of\n" +
" --docker-metrics, --docker-metrics-at <addr>, or other options like \n" +
" --report-graphite-to <addr> and --annotators <config>\n" +
" For more details, see run 'nb help docker-metrics'");
" the destination for metrics and annotations. Please select only one of\n" +
" --docker-metrics, --docker-metrics-at <addr>, or other options like \n" +
" --report-graphite-to <addr> and --annotators <config>\n" +
" For more details, see run 'nb help docker-metrics'");
String graphiteMetricsAddress = null;
@ -229,28 +239,44 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
NBCLI.logger.info("Docker metrics is enabled. Docker must be installed for this to work");
final DockerMetricsManager dmh = new DockerMetricsManager();
final Map<String, String> dashboardOptions = Map.of(
DockerMetricsManager.GRAFANA_TAG, globalOptions.getDockerGrafanaTag(),
DockerMetricsManager.PROM_TAG, globalOptions.getDockerPromTag(),
DockerMetricsManager.TSDB_RETENTION, String.valueOf(globalOptions.getDockerPromRetentionDays()),
DockerMetricsManager.GRAPHITE_SAMPLE_EXPIRY, "10m",
DockerMetricsManager.GRAPHITE_CACHE_SIZE, "5000",
DockerMetricsManager.GRAPHITE_LOG_LEVEL, globalOptions.getGraphiteLogLevel(),
DockerMetricsManager.GRAPHITE_LOG_FORMAT, "logfmt"
DockerMetricsManager.GRAFANA_TAG, globalOptions.getDockerGrafanaTag(),
DockerMetricsManager.PROM_TAG, globalOptions.getDockerPromTag(),
DockerMetricsManager.TSDB_RETENTION, String.valueOf(globalOptions.getDockerPromRetentionDays()),
DockerMetricsManager.GRAPHITE_SAMPLE_EXPIRY, "10m",
DockerMetricsManager.GRAPHITE_CACHE_SIZE, "5000",
DockerMetricsManager.GRAPHITE_LOG_LEVEL, globalOptions.getGraphiteLogLevel(),
DockerMetricsManager.GRAPHITE_LOG_FORMAT, "logfmt"
);
dmh.startMetrics(dashboardOptions);
final String warn = "Docker Containers are started, for grafana and prometheus, hit" +
" these urls in your browser: http://<host>:3000 and http://<host>:9090";
" these urls in your browser: http://<host>:3000 and http://<host>:9090";
NBCLI.logger.warn(warn);
graphiteMetricsAddress = "localhost";
} else if (null != dockerMetricsAt) graphiteMetricsAddress = dockerMetricsAt;
} else if (null != dockerMetricsAt) {
graphiteMetricsAddress = dockerMetricsAt;
}
if (null != graphiteMetricsAddress) {
reportGraphiteTo = graphiteMetricsAddress + ":9109";
annotatorsConfig = "[{type:'log',level:'info'},{type:'grafana',baseurl:'http://" + graphiteMetricsAddress + ":3000" +
"/'," +
"tags:'appname:nosqlbench',timeoutms:5000,onerror:'warn'}]";
} else annotatorsConfig = "[{type:'log',level:'info'}]";
if (annotatorsConfig == null || annotatorsConfig.isBlank()) {
List<Map<String, String>> annotatorsConfigs = new ArrayList<>();
annotatorsConfigs.add(Map.of(
"type", "log",
"level", "info"
));
if (null != graphiteMetricsAddress) {
reportGraphiteTo = graphiteMetricsAddress + ":9109";
annotatorsConfigs.add(Map.of(
"type", "grafana",
"baseurl", "http://" + graphiteMetricsAddress + ":3000",
"tags", "appname:nosqlbench",
"timeoutms", "5000",
"onerror", "warn"
));
}
Gson gson = new GsonBuilder().create();
annotatorsConfig = gson.toJson(annotatorsConfigs);
}
final NBCLIOptions options = new NBCLIOptions(args);
NBCLI.logger = LogManager.getLogger("NBCLI");
@ -313,19 +339,19 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
NBCLI.logger.debug(() -> "user requests to copy out " + resourceToCopy);
Optional<Content<?>> tocopy = NBIO.classpath()
.searchPrefixes("activities")
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCopy).extensionSet(RawOpsLoader.YAML_EXTENSIONS).first();
.searchPrefixes("activities")
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCopy).extensionSet(RawOpsLoader.YAML_EXTENSIONS).first();
if (tocopy.isEmpty()) tocopy = NBIO.classpath()
.searchPrefixes().searchPrefixes(options.wantsIncludes())
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCopy).first();
.searchPrefixes().searchPrefixes(options.wantsIncludes())
.searchPrefixes(options.wantsIncludes())
.pathname(resourceToCopy).first();
final Content<?> data = tocopy.orElseThrow(
() -> new BasicError(
"Unable to find " + resourceToCopy +
" in classpath to copy out")
() -> new BasicError(
"Unable to find " + resourceToCopy +
" in classpath to copy out")
);
final Path writeTo = Path.of(data.asPath().getFileName().toString());
@ -363,7 +389,7 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
if (options.wantsTopicalHelp()) {
final Optional<String> helpDoc = MarkdownFinder.forHelpTopic(options.wantsTopicalHelpFor());
System.out.println(helpDoc.orElseThrow(
() -> new RuntimeException("No help could be found for " + options.wantsTopicalHelpFor())
() -> new RuntimeException("No help could be found for " + options.wantsTopicalHelpFor())
));
return NBCLI.EXIT_OK;
}
@ -378,12 +404,12 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
NBCLI.logger.debug("initializing annotators with config:'{}'", annotatorsConfig);
Annotators.init(annotatorsConfig);
Annotators.recordAnnotation(
Annotation.newBuilder()
.session(sessionName)
.now()
.layer(Layer.CLI)
.detail("cli", String.join("\n", args))
.build()
Annotation.newBuilder()
.element(this)
.now()
.layer(Layer.Session)
.detail("cli", String.join("\n", args))
.build()
);
if ((null != reportPromPushTo) || (null != reportGraphiteTo) || (null != options.wantsReportCsvTo())) {
@ -410,13 +436,13 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
}
for (
final LoggerConfigData histoLogger : options.getHistoLoggerConfigs())
final LoggerConfigData histoLogger : options.getHistoLoggerConfigs())
ActivityMetrics.addHistoLogger(sessionName, histoLogger.pattern, histoLogger.file, histoLogger.interval);
for (
final LoggerConfigData statsLogger : options.getStatsLoggerConfigs())
final LoggerConfigData statsLogger : options.getStatsLoggerConfigs())
ActivityMetrics.addStatsLogger(sessionName, statsLogger.pattern, statsLogger.file, statsLogger.interval);
for (
final LoggerConfigData classicConfigs : options.getClassicHistoConfigs())
final LoggerConfigData classicConfigs : options.getClassicHistoConfigs())
ActivityMetrics.addClassicHistos(sessionName, classicConfigs.pattern, classicConfigs.file, classicConfigs.interval);
// intentionally not shown for warn-only
@ -429,21 +455,21 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
}
final Scenario scenario = new Scenario(
sessionName,
options.getScriptFile(),
options.getScriptingEngine(),
options.getProgressSpec(),
options.wantsStackTraces(),
options.wantsCompileScript(),
options.getReportSummaryTo(),
String.join("\n", args),
options.getLogsDirectory(),
Maturity.Unspecified,
this);
sessionName,
options.getScriptFile(),
options.getScriptingEngine(),
options.getProgressSpec(),
options.wantsStackTraces(),
options.wantsCompileScript(),
options.getReportSummaryTo(),
String.join("\n", args),
options.getLogsDirectory(),
Maturity.Unspecified,
this);
final ScriptBuffer buffer = new BasicScriptBuffer()
.add(options.getCommands()
.toArray(new Cmd[0]));
.add(options.getCommands()
.toArray(new Cmd[0]));
final String scriptData = buffer.getParsedScript();
if (options.wantsShowScript()) {

View File

@ -16,20 +16,19 @@
package io.nosqlbench.engine.cli;
import io.nosqlbench.api.config.NBLabelSpec;
import io.nosqlbench.api.config.NBLabels;
import io.nosqlbench.api.engine.util.Unit;
import io.nosqlbench.api.errors.BasicError;
import io.nosqlbench.api.logging.NBLogLevel;
import io.nosqlbench.api.system.NBEnvironment;
import io.nosqlbench.api.system.NBStatePath;
import io.nosqlbench.engine.api.metrics.IndicatorMode;
import io.nosqlbench.engine.cli.Cmd.CmdType;
import io.nosqlbench.engine.core.lifecycle.scenario.Scenario.Engine;
import io.nosqlbench.nb.annotations.Maturity;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermissions;
import java.security.InvalidParameterException;
import java.util.*;
import java.util.stream.Collectors;
@ -44,14 +43,13 @@ public class NBCLIOptions {
private static final String NB_STATE_DIR = "--statedir";
private static final String NB_STATEDIR_PATHS = "$NBSTATEDIR:$PWD/.nosqlbench:$HOME/.nosqlbench";
public static final String ARGS_FILE_DEFAULT = "$NBSTATEDIR/argsfile";
private static final String INCLUDE = "--include";
private static final String userHome = System.getProperty("user.home");
private static final Map<String,String> DEFAULT_LABELS=Map.of("appname","nosqlbench");
private static final Map<String, String> DEFAULT_LABELS = Map.of("appname", "nosqlbench");
private static final String METRICS_PREFIX = "--metrics-prefix";
private static final String ANNOTATE_EVENTS = "--annotate";
private static final String ANNOTATORS_CONFIG = "--annotators";
@ -136,7 +134,7 @@ public class NBCLIOptions {
// private static final String DEFAULT_CONSOLE_LOGGING_PATTERN = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n";
private final Map<String,String> labels = new LinkedHashMap<>(DEFAULT_LABELS);
private NBLabels labels = NBLabels.forKV();
private final List<Cmd> cmdList = new ArrayList<>();
private int logsMax;
private boolean wantsVersionShort;
@ -151,7 +149,8 @@ public class NBCLIOptions {
private int reportInterval = 10;
private String metricsPrefix = "nosqlbench";
private String wantsMetricsForActivity;
private String sessionName = "";
private String sessionName = "SESSIONCODE";
// private String sessionName = "scenario_%tY%tm%td_%tH%tM%tS_%tL";
private boolean showScript;
private NBLogLevel consoleLevel = NBLogLevel.WARN;
private final List<String> histoLoggerConfigs = new ArrayList<>();
@ -185,9 +184,8 @@ public class NBCLIOptions {
private String[] annotateEvents = {"ALL"};
private String dockerMetricsHost;
private String annotatorsConfig = "";
private String statedirs = NBCLIOptions.NB_STATEDIR_PATHS;
private String statedirs = NBStatePath.NB_STATEDIR_PATHS;
private Path statepath;
private final List<String> statePathAccesses = new ArrayList<>();
private final String hdrForChartFileName = NBCLIOptions.DEFAULT_CHART_HDR_LOG_NAME;
private String dockerPromRetentionDays = "3650d";
private String reportSummaryTo = NBCLIOptions.REPORT_SUMMARY_TO_DEFAULT;
@ -210,8 +208,8 @@ public class NBCLIOptions {
return this.annotatorsConfig;
}
public Map<String,String> getLabelMap() {
return Collections.unmodifiableMap(this.labels);
public NBLabels getLabelMap() {
return this.labels;
}
public String getChartHdrFileName() {
@ -305,8 +303,7 @@ public class NBCLIOptions {
nonincludes.addLast(arglist.removeFirst());
}
}
statedirs = (null != this.statedirs) ? statedirs : NBCLIOptions.NB_STATEDIR_PATHS;
setStatePath();
this.statepath = NBStatePath.initialize(statedirs);
arglist = nonincludes;
nonincludes = new LinkedList<>();
@ -336,7 +333,7 @@ public class NBCLIOptions {
case NBCLIArgsFile.ARGS_FILE_REQUIRED:
case NBCLIArgsFile.ARGS_PIN:
case NBCLIArgsFile.ARGS_UNPIN:
if (null == this.statepath) this.setStatePath();
this.statepath = NBStatePath.initialize(statedirs);
arglist = argsfile.process(arglist);
break;
case NBCLIOptions.ANSI:
@ -487,63 +484,13 @@ public class NBCLIOptions {
}
private void setLabels(String labeldata) {
this.labels.clear();
this.labels = NBLabels.forKV();
addLabels(labeldata);
}
private void addLabels(String labeldata) {
Map<String,String> newLabels = parseLabels(labeldata);
this.labels.putAll(newLabels);
}
private Map<String, String> parseLabels(String labeldata) {
Map<String,String> setLabelsTo = new LinkedHashMap<>();
for (String component : labeldata.split("[,; ]")) {
String[] parts = component.split("\\W", 2);
if (parts.length!=2) {
throw new BasicError("Unable to parse labels to set:" + labeldata);
}
setLabelsTo.put(parts[0],parts[1]);
}
return setLabelsTo;
}
private Path setStatePath() {
if (0 < statePathAccesses.size())
throw new BasicError("The state dir must be set before it is used by other\n" +
" options. If you want to change the statedir, be sure you do it before\n" +
" dependent options. These parameters were called before this --statedir:\n" +
this.statePathAccesses.stream().map(s -> "> " + s).collect(Collectors.joining("\n")));
if (null != this.statepath) return statepath;
final List<String> paths = NBEnvironment.INSTANCE.interpolateEach(":", this.statedirs);
Path selected = null;
for (final String pathName : paths) {
final Path path = Path.of(pathName);
if (Files.exists(path)) {
if (Files.isDirectory(path)) {
selected = path;
break;
}
System.err.println("ERROR: possible state dir path is not a directory: '" + path + '\'');
}
}
if (null == selected) selected = Path.of(paths.get(paths.size() - 1));
if (!Files.exists(selected)) try {
Files.createDirectories(
selected,
PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwxrwx---"))
);
} catch (final IOException e) {
throw new BasicError("Could not create state directory at '" + selected + "': " + e.getMessage());
}
NBEnvironment.INSTANCE.put(NBEnvironment.NBSTATEDIR, selected.toString());
return selected;
NBLabels newLabels = NBLabelSpec.parseLabels(labeldata);
this.labels = this.labels.and(newLabels);
}
private void parseAllOptions(final String[] args) {
@ -846,14 +793,10 @@ public class NBCLIOptions {
public String getProgressSpec() {
final ProgressSpec spec = this.parseProgressSpec(progressSpec);// sanity check
// System.err.println("Console is already logging info or more, so progress data on console is " +
// "suppressed.");
if (IndicatorMode.console == spec.indicatorMode)
if (consoleLevel.isGreaterOrEqualTo(NBLogLevel.INFO)) spec.indicatorMode = IndicatorMode.logonly;
else // System.err.println("Command line includes script calls, so progress data on console is " +
// "suppressed.");
if (cmdList.stream().anyMatch(cmd -> CmdType.script == cmd.getCmdType()))
spec.indicatorMode = IndicatorMode.logonly;
else if (cmdList.stream().anyMatch(cmd -> CmdType.script == cmd.getCmdType()))
spec.indicatorMode = IndicatorMode.logonly;
return spec.toString();
}

View File

@ -103,10 +103,11 @@ public class NBCLIScenarioParserTest {
List<Cmd> cmds = opts.getCommands();
assertThat(cmds.size()).isEqualTo(1);
assertThat(cmds.get(0).getParams()).isEqualTo(Map.of(
"alias", "scenariotest_templatetest_withtemplate",
"alias", "with_template",
"cycles", "20",
"cycles-test", "20",
"driver", "stdout",
"labels","workload:scenario_test",
"workload", "scenario-test"
));
}
@ -117,9 +118,10 @@ public class NBCLIScenarioParserTest {
List<Cmd> cmds = opts.getCommands();
assertThat(cmds.size()).isEqualTo(1);
assertThat(cmds.get(0).getParams()).isEqualTo(Map.of(
"alias", "scenariotest_schemaonly_schema",
"alias", "schema",
"cycles-test", "20",
"driver", "stdout",
"labels","workload:scenario_test",
"tags", "block:\"schema.*\"",
"workload", "scenario-test"
));
@ -158,7 +160,7 @@ public class NBCLIScenarioParserTest {
@Test
public void testSanitizer() {
String sanitized = NBCLIScenarioParser.sanitize("A-b,c_d");
assertThat(sanitized).isEqualTo("Abcd");
assertThat(sanitized).isEqualTo("A_bc_d");
}
@Test
@ -167,9 +169,10 @@ public class NBCLIScenarioParserTest {
List<Cmd> cmds = opts.getCommands();
assertThat(cmds.size()).isEqualTo(1);
assertThat(cmds.get(0).getParams()).isEqualTo(Map.of(
"alias", "scenariotest_schemaonly_schema",
"alias", "schema",
"cycles-test", "20",
"driver", "stdout",
"labels","workload:scenario_test",
"tags", "block:\"schema.*\"",
"workload", "scenario-test"
));

View File

@ -33,12 +33,6 @@
</description>
<dependencies>
<dependency>
<groupId>io.nosqlbench</groupId>
<artifactId>engine-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>io.nosqlbench</groupId>
<artifactId>nb-api</artifactId>

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.
@ -126,6 +126,8 @@ public class GrafanaClientConfig {
private URI makeUri(String pathAndQuery) {
try {
String baseUri = getBaseUri().toString();
baseUri = (!baseUri.endsWith("/")&&!pathAndQuery.startsWith("/")) ? baseUri+"/" : baseUri;
return new URI(getBaseUri().toString() + pathAndQuery);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
@ -145,13 +147,16 @@ public class GrafanaClientConfig {
public GrafanaClientConfig setBaseUri(String baseuri) {
try {
baseuri = baseuri.endsWith("/") ? baseuri : baseuri + "/";
URI uri = new URI(baseuri);
String userinfo = uri.getRawUserInfo();
if (userinfo != null) {
String[] unpw = userinfo.split(":");
basicAuth(unpw[0], unpw.length == 2 ? unpw[1] : "");
uri = new URI(baseuri.replace(userinfo + "@", ""));
String expanded = baseuri.replace(userinfo + "@", "");
uri = new URI(expanded);
}
this.baseUrl = uri;
} catch (URISyntaxException e) {

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 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.engine.clients.grafana;
import io.nosqlbench.api.apps.BundledApp;
import io.nosqlbench.api.system.NBEnvironment;
import io.nosqlbench.nb.annotations.Service;
import picocli.CommandLine;
@Service(value = BundledApp.class,selector = "grafana-apikey")
@CommandLine.Command(
name="gafana-apikey",
description = "create and cache a grafana apikey for a given grafana server"
)
public class GrafanaTokenAuthenticator implements BundledApp {
@CommandLine.Parameters
private final String keyfile = NBEnvironment.INSTANCE.get("apikeyfile");
@Override
public int applyAsInt(String[] value) {
return 0;
}
}

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.
@ -21,12 +21,12 @@ import io.nosqlbench.api.annotations.Annotator;
import io.nosqlbench.api.config.params.ParamsParser;
import io.nosqlbench.api.config.standard.*;
import io.nosqlbench.api.errors.BasicError;
import io.nosqlbench.api.errors.OnError;
import io.nosqlbench.api.metadata.SystemId;
import io.nosqlbench.engine.clients.grafana.GrafanaClient;
import io.nosqlbench.engine.clients.grafana.GrafanaClientConfig;
import io.nosqlbench.engine.clients.grafana.transfer.GAnnotation;
import io.nosqlbench.nb.annotations.Service;
import io.nosqlbench.api.errors.OnError;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -36,6 +36,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Pattern;
@Service(value = Annotator.class, selector = "grafana")
public class GrafanaMetricsAnnotator implements Annotator, NBConfigurable {
@ -58,9 +59,12 @@ public class GrafanaMetricsAnnotator implements Annotator, NBConfigurable {
ga.setTime(annotation.getStart());
ga.setTimeEnd(annotation.getEnd());
annotation.getLabels().forEach((k, v) -> {
annotation.getLabels().onlyTypes().asMap().forEach((k, v) -> {
ga.getTags().add(k + ":" + v);
});
annotation.getLabels().onlyInstances().asMap().forEach((k,v)->{
ga.addText(" " + k + ":" + v);
});
ga.getTags().add("layer:" + annotation.getLayer().toString());
if (annotation.getStart() == annotation.getEnd()) {
@ -69,15 +73,12 @@ public class GrafanaMetricsAnnotator implements Annotator, NBConfigurable {
ga.getTags().add("span:interval");
}
Map<String, String> labels = annotation.getLabels();
Map<String, String> labels = annotation.getLabels().asMap();
Optional.ofNullable(labels.get("alertId"))
.map(Integer::parseInt).ifPresent(ga::setAlertId);
ga.setText(annotation.toString());
annotation.getSession();
ga.addText(annotation.toString());
// Target
Optional.ofNullable(labels.get("type"))
@ -175,7 +176,8 @@ public class GrafanaMetricsAnnotator implements Annotator, NBConfigurable {
public NBConfigModel getConfigModel() {
return ConfigModel.of(this.getClass())
.add(Param.required("baseurl", String.class)
.setDescription("The base url of the grafana node, like http://localhost:3000/"))
.setDescription("The base url of the grafana node, like http://localhost:3000/")
.setRegex(Pattern.compile("http.+\\\\/")))
.add(Param.defaultTo("apikeyfile", "$NBSTATEDIR/grafana/grafana_apikey")
.setDescription("The file that contains the api key, supersedes apikey"))
.add(Param.optional("apikey", String.class)

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.
@ -121,8 +121,8 @@ public class GAnnotation {
return text;
}
public void setText(String text) {
this.text = text;
public void addText(String text) {
this.text = this.text == null ? text : this.text + "\n" + text;
}
public String getMetric() {

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.
@ -36,7 +36,7 @@ public class GrafanaClientTest {
client.getConfig().basicAuth("admin", "admin");
GAnnotation a = new GAnnotation();
a.setDashboardId(2);
a.setText("testingAnnotation");
a.addText("testingAnnotation");
GAnnotation created = client.createAnnotation(a);
logger.info(created);
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 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.engine.clients.grafana.annotator;
import io.nosqlbench.api.annotations.Annotation;
import io.nosqlbench.api.annotations.Layer;
import io.nosqlbench.api.config.NBLabeledElement;
import io.nosqlbench.api.config.NBLabels;
import io.nosqlbench.api.system.NBStatePath;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.Map;
public class GrafanaMetricsAnnotatorTest implements NBLabeledElement {
@Test
@Disabled
public void testPost() {
String ipaddr="CHANGEME";
NBStatePath.initialize();
GrafanaMetricsAnnotator ganno = new GrafanaMetricsAnnotator();
ganno.applyConfig(ganno.getConfigModel().apply(Map.of(
"baseurl","http://"+ipaddr+":3000/",
"tags","appname:nosqlbench",
"timeoutms","5000",
"onerror","warn"
)));
ganno.recordAnnotation(Annotation.newBuilder()
.element(this)
.now()
.layer(Layer.Session)
.build());
}
@Override
public NBLabels getLabels() {
return NBLabels.forMap(Map.of("testlabelname","testlabelvalue"));
}
}

View File

@ -15,6 +15,8 @@
*/
package io.nosqlbench.engine.core.lifecycle.activity;
import io.nosqlbench.api.config.NBLabeledElement;
import io.nosqlbench.api.config.NBLabels;
import io.nosqlbench.engine.api.activityapi.core.*;
import io.nosqlbench.engine.api.activityimpl.MotorState;
import io.nosqlbench.api.annotations.Annotation;
@ -51,7 +53,7 @@ import java.util.stream.Collectors;
* This allows the state tracking to work consistently for all observers.</p>
*/
public class ActivityExecutor implements ActivityController, ParameterMap.Listener, ProgressCapable, Callable<ExecutionResult> {
public class ActivityExecutor implements NBLabeledElement, ActivityController, ParameterMap.Listener, ProgressCapable, Callable<ExecutionResult> {
// TODO Encapsulate valid state transitions to be only modifiable within the appropriate type view.
@ -99,12 +101,9 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
logger.info(() -> "stopped: " + this.getActivityDef().getAlias() + " with " + motors.size() + " slots");
Annotators.recordAnnotation(Annotation.newBuilder()
.session(sessionId)
.element(this)
.interval(this.startedAt, this.stoppedAt)
.layer(Layer.Activity)
.label("alias", getActivityDef().getAlias())
.label("driver", getActivityDef().getActivityType())
.label("workload", getActivityDef().getParams().getOptionalString("workload").orElse("none"))
.detail("params", getActivityDef().toString())
.build()
);
@ -126,12 +125,9 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
logger.info(() -> "stopped: " + this.getActivityDef().getAlias() + " with " + motors.size() + " slots");
Annotators.recordAnnotation(Annotation.newBuilder()
.session(sessionId)
.element(this)
.interval(this.startedAt, this.stoppedAt)
.layer(Layer.Activity)
.label("alias", getActivityDef().getAlias())
.label("driver", getActivityDef().getActivityType())
.label("workload", getActivityDef().getParams().getOptionalString("workload").orElse("none"))
.detail("params", getActivityDef().toString())
.build()
);
@ -505,12 +501,9 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
logger.info(() -> "starting activity " + activity.getAlias() + " for cycles " + activity.getCycleSummary());
Annotators.recordAnnotation(Annotation.newBuilder()
.session(sessionId)
.element(this)
.now()
.layer(Layer.Activity)
.label("alias", getActivityDef().getAlias())
.label("driver", getActivityDef().getActivityType())
.label("workload", getActivityDef().getParams().getOptionalString("workload").orElse("none"))
.detail("params", getActivityDef().toString())
.build()
);
@ -533,4 +526,8 @@ public class ActivityExecutor implements ActivityController, ParameterMap.Listen
}
@Override
public NBLabels getLabels() {
return activity.getLabels();
}
}

View File

@ -80,10 +80,9 @@ public class Scenario implements Callable<ExecutionMetricsResult>, NBLabeledElem
return Optional.ofNullable(result);
}
@Override
public NBLabels getLabels() {
return this.parentComponent.getLabels().and("scenario", this.scenarioName);
return this.parentComponent.getLabels().andTypes("scenario", this.scenarioName);
}
public enum State {
@ -139,18 +138,9 @@ public class Scenario implements Callable<ExecutionMetricsResult>, NBLabeledElem
}
public static Scenario forTesting(final String name, final Engine engine, final String reportSummaryTo, final Maturity minMaturity) {
return new Scenario(name, null, engine, "console:10s", true, true, reportSummaryTo, "", Path.of("logs"), minMaturity, NBLabeledElement.forKV("test-name", "name"));
return new Scenario(name, null, engine, "console:10s", true, true, reportSummaryTo, "", Path.of("logs"), minMaturity, NBLabeledElement.forKV("test_name", "name"));
}
// public Scenario(final String name, final Engine engine, final String reportSummaryTo, final Maturity minMaturity) {
// scenarioName = name;
// this.reportSummaryTo = reportSummaryTo;
// this.engine = engine;
// commandLine = "";
// this.minMaturity = minMaturity;
// logsPath = Path.of("logs");
// }
//
public Scenario setLogger(final Logger logger) {
this.logger = logger;
return this;
@ -259,7 +249,7 @@ public class Scenario implements Callable<ExecutionMetricsResult>, NBLabeledElem
this.startedAtMillis = System.currentTimeMillis();
Annotators.recordAnnotation(
Annotation.newBuilder()
.session(scenarioName)
.element(this)
.now()
.layer(Layer.Scenario)
.detail("engine", engine.toString())
@ -358,10 +348,10 @@ public class Scenario implements Callable<ExecutionMetricsResult>, NBLabeledElem
// We report the scenario state via annotation even for short runs
final Annotation annotation = Annotation.newBuilder()
.session(scenarioName)
.element(this)
.interval(startedAtMillis, this.endedAtMillis)
.layer(Layer.Scenario)
.label("state", state.toString())
// .labels("state", state.toString())
.detail("command_line", commandLine)
.build();

View File

@ -68,15 +68,6 @@ public class ScenarioController implements NBLabeledElement {
* @param activityDef string in alias=value1;driver=value2;... format
*/
public synchronized void start(ActivityDef activityDef) {
Annotators.recordAnnotation(Annotation.newBuilder()
.session(scenario.getScenarioName())
.now()
.layer(Layer.Activity)
.label("alias", activityDef.getAlias())
.detail("command", "start")
.detail("params", activityDef.toString())
.build());
doStartActivity(activityDef);
}
@ -84,6 +75,14 @@ public class ScenarioController implements NBLabeledElement {
private synchronized ActivityRuntimeInfo doStartActivity(ActivityDef activityDef) {
if (!this.activityInfoMap.containsKey(activityDef.getAlias())) {
Activity activity = this.activityLoader.loadActivity(activityDef, this);
Annotators.recordAnnotation(Annotation.newBuilder()
.element(activity)
.now()
.layer(Layer.Activity)
.detail("params", activityDef.toString())
.build());
ActivityExecutor executor = new ActivityExecutor(activity, this.scenario.getScenarioName());
Future<ExecutionResult> startedActivity = activitiesExecutor.submit(executor);
ActivityRuntimeInfo activityRuntimeInfo = new ActivityRuntimeInfo(activity, startedActivity, executor);
@ -125,14 +124,6 @@ public class ScenarioController implements NBLabeledElement {
* @param activityDef A definition for an activity to run
*/
public synchronized void run(ActivityDef activityDef, long timeoutMs) {
Annotators.recordAnnotation(Annotation.newBuilder()
.session(this.scenario.getScenarioName())
.now()
.layer(Layer.Activity)
.label("alias", activityDef.getAlias())
.detail("command", "run")
.detail("params", activityDef.toString())
.build());
doStartActivity(activityDef);
awaitActivity(activityDef, timeoutMs);
@ -179,14 +170,6 @@ public class ScenarioController implements NBLabeledElement {
* @param activityDef An activity def, including at least the alias parameter.
*/
public synchronized void stop(ActivityDef activityDef) {
Annotators.recordAnnotation(Annotation.newBuilder()
.session(this.scenario.getScenarioName())
.now()
.layer(Layer.Activity)
.label("alias", activityDef.getAlias())
.detail("command", "stop")
.detail("params", activityDef.toString())
.build());
ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(activityDef.getAlias());
if (null == runtimeInfo) {
@ -196,6 +179,14 @@ public class ScenarioController implements NBLabeledElement {
scenariologger.debug("STOP {}", activityDef.getAlias());
runtimeInfo.stopActivity();
Annotators.recordAnnotation(Annotation.newBuilder()
.element(runtimeInfo.getActivity())
.now()
.layer(Layer.Activity)
.detail("command", "stop")
.detail("params", activityDef.toString())
.build());
}
/**
@ -240,20 +231,21 @@ public class ScenarioController implements NBLabeledElement {
* @param activityDef An activity def, including at least the alias parameter.
*/
public synchronized void forceStop(ActivityDef activityDef) {
Annotators.recordAnnotation(Annotation.newBuilder()
.session(this.scenario.getScenarioName())
.now()
.layer(Layer.Activity)
.label("alias", activityDef.getAlias())
.detail("command", "forceStop")
.detail("params", activityDef.toString())
.build());
ActivityRuntimeInfo runtimeInfo = this.activityInfoMap.get(activityDef.getAlias());
if (null == runtimeInfo) {
throw new RuntimeException("could not force stop missing activity:" + activityDef);
}
Annotators.recordAnnotation(Annotation.newBuilder()
.element(runtimeInfo.getActivity())
.now()
.layer(Layer.Activity)
.detail("command", "forceStop")
.detail("params", activityDef.toString())
.build());
scenariologger.debug("FORCE STOP {}", activityDef.getAlias());
runtimeInfo.forceStopActivity();

View File

@ -66,6 +66,7 @@ public class LoggerConfig extends ConfigurationFactory {
* we squelch them to some reasonable level so they aren't a nuisance.
*/
public static Map<String, Level> BUILTIN_OVERRIDES = Map.of(
// ERROR StatusConsoleListener Unable to locate appender "SCENARIO_APPENDER" for logger config "oshi.util"
"oshi.util", Level.INFO
);

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.
@ -16,6 +16,9 @@
package io.nosqlbench.api.annotations;
import io.nosqlbench.api.config.NBLabeledElement;
import io.nosqlbench.api.config.NBLabels;
import java.util.Map;
/**
@ -30,11 +33,7 @@ import java.util.Map;
* NoSQLBench. It is up to the downstream consumers to map these
* to concrete fields or identifiers as appropriate.
*/
public interface Annotation {
/**
* @return The named session that the annotation is associated with
*/
String getSession();
public interface Annotation extends NBLabeledElement {
/**
* If this is the same as {@link #getEnd()}, then the annotation is
@ -74,7 +73,7 @@ public interface Annotation {
*
* @return The labels map
*/
Map<String, String> getLabels();
NBLabels getLabels();
/**
* The details are an ordered map of all the content that you would want the user to see.
@ -83,15 +82,15 @@ public interface Annotation {
*/
Map<String, String> getDetails();
static AnnotationBuilderFacets.WantsSession newBuilder() {
static AnnotationBuilderFacets.WantsLabeledElement newBuilder() {
return new AnnotationBuilder();
}
/**
* This should return {@link Span#interval} if the span of time is not an instant, and
* {@link Span#instant}, otherwise.
* This should return {@link Temporal#interval} if the span of time is not an instant, and
* {@link Temporal#instant}, otherwise.
*/
Span getSpan();
Temporal getTemporal();
String asJson();

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.
@ -16,6 +16,8 @@
package io.nosqlbench.api.annotations;
import io.nosqlbench.api.config.NBLabeledElement;
import java.time.ZoneId;
import java.util.LinkedHashMap;
import java.util.TimeZone;
@ -24,15 +26,15 @@ public class AnnotationBuilder implements AnnotationBuilderFacets.All {
private String session;
private long start;
private long end;
private final LinkedHashMap<String, String> labels = new LinkedHashMap<>();
private final LinkedHashMap<String, String> details = new LinkedHashMap<>();
private Layer layer;
private final TimeZone timezone = TimeZone.getTimeZone(ZoneId.of("GMT"));
private NBLabeledElement element;
@Override
public AnnotationBuilder layer(Layer layer) {
this.layer = layer;
this.label("layer", layer.toString());
return this;
}
@ -68,12 +70,6 @@ public class AnnotationBuilder implements AnnotationBuilderFacets.All {
}
@Override
public AnnotationBuilder label(String name, String value) {
this.labels.put(name, value);
return this;
}
@Override
public AnnotationBuilderFacets.WantsMoreDetailsOrBuild detail(String name, String value) {
this.details.put(name, value);
@ -82,14 +78,13 @@ public class AnnotationBuilder implements AnnotationBuilderFacets.All {
@Override
public Annotation build() {
return new MutableAnnotation(timezone, session, layer, start, end, labels, details).asReadOnly();
return new MutableAnnotation(timezone, session, layer, start, end, element, details).asReadOnly();
}
@Override
public AnnotationBuilderFacets.WantsInterval session(String session) {
this.session = session;
public AnnotationBuilderFacets.WantsInterval element(NBLabeledElement element) {
this.element = element;
return this;
}
}

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.
@ -16,17 +16,19 @@
package io.nosqlbench.api.annotations;
import io.nosqlbench.api.config.NBLabeledElement;
public interface AnnotationBuilderFacets {
interface All extends
WantsSession, WantsInterval, WantsLayer, WantsLabels, WantsMoreDetailsOrBuild, WantsMoreLabelsOrDetails {
WantsLabeledElement, WantsInterval, WantsLayer, WantsMoreDetailsOrBuild {
}
interface WantsSession {
interface WantsLabeledElement {
/**
* The session is the global name of a NoSQLBench process which run a scenario. It is required.
*/
WantsInterval session(String session);
WantsInterval element(NBLabeledElement element);
}
interface WantsInterval {
@ -50,22 +52,11 @@ public interface AnnotationBuilderFacets {
}
interface WantsLayer {
WantsMoreLabelsOrDetails layer(Layer layer);
}
interface WantsLabels {
WantsMoreLabelsOrDetails label(String name, String value);
}
interface WantsMoreLabelsOrDetails {
WantsMoreLabelsOrDetails label(String name, String value);
WantsMoreDetailsOrBuild detail(String name, String value);
WantsMoreDetailsOrBuild layer(Layer layer);
}
interface WantsMoreDetailsOrBuild {
WantsMoreDetailsOrBuild detail(String name, String value);
Annotation build();
}

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.
@ -22,7 +22,7 @@ public enum Layer {
* Events which describe command line arguments, such as parsing,
* named scenario mapping, or critical errors
*/
CLI,
Session,
/**
* Events which describe scenario execution, such as parameters,

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.
@ -19,12 +19,16 @@ package io.nosqlbench.api.annotations;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import io.nosqlbench.api.config.NBLabeledElement;
import io.nosqlbench.api.config.NBLabels;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TimeZone;
public class MutableAnnotation implements Annotation {
@ -41,13 +45,11 @@ public class MutableAnnotation implements Annotation {
@Expose
private long end = 0L;
@Expose
private Map<String, String> labels = new LinkedHashMap<>();
@Expose
private Map<String, String> details = new LinkedHashMap<>();
private final ZoneId zoneid = ZoneId.of("GMT");
private NBLabeledElement element;
public MutableAnnotation(
TimeZone timezone,
@ -55,50 +57,40 @@ public class MutableAnnotation implements Annotation {
Layer layer,
long start,
long end,
LinkedHashMap<String, String> labels,
NBLabeledElement element,
LinkedHashMap<String, String> details) {
setLabels(labels);
setElement(element);
setSession(session);
setLayer(layer);
setStart(start);
setEnd(end);
setDetails(details);
labels.put("appname", "nosqlbench");
}
private void setElement(NBLabeledElement element) {
this.element = element;
}
public void setSession(String sessionName) {
this.session = sessionName;
this.labels.put("session", sessionName);
}
public void setStart(long intervalStart) {
this.start = intervalStart;
this.labels.put("span", getSpan().toString());
}
public void setEnd(long intervalEnd) {
this.end = intervalEnd;
this.labels.put("span", getSpan().toString());
}
public void setLabels(Map<String, String> labels) {
this.labels = labels;
}
public void setLayer(Layer layer) {
this.layer = layer;
this.labels.put("layer", layer.toString());
}
public void setDetails(Map<String, String> details) {
this.details = details;
}
@Override
public String getSession() {
return session;
}
@Override
public long getStart() {
return start;
@ -115,11 +107,8 @@ public class MutableAnnotation implements Annotation {
}
@Override
public Map<String, String> getLabels() {
// if (!labels.containsKey("span")) {
// labels.put("span",getSpan().toString());
// }
return labels;
public NBLabels getLabels() {
return element.getLabels();
}
@Override
@ -130,7 +119,6 @@ public class MutableAnnotation implements Annotation {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("session: ").append(getSession()).append("\n");
ZonedDateTime startTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(getStart()), zoneid);
ZonedDateTime endTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(getStart()), zoneid);
@ -144,17 +132,17 @@ public class MutableAnnotation implements Annotation {
}
sb.append("]\n");
sb.append("span:").append(getSpan()).append("\n");
sb.append("span:").append(getTemporal()).append("\n");
sb.append("details:\n");
formatMap(sb, getDetails());
sb.append("labels:\n");
formatMap(sb, getLabels());
formatMap(sb, getLabels().asMap());
return sb.toString();
}
private void formatMap(StringBuilder sb, Map<String, String> details) {
details.forEach((k, v) -> {
sb.append(" ").append(k).append(": ");
sb.append(" ").append(k).append(":");
if (v.contains("\n")) {
sb.append("\n");
@ -164,7 +152,7 @@ public class MutableAnnotation implements Annotation {
}
// Arrays.stream(lines).sequential().map(s -> " "+s+"\n").forEach(sb::append);
} else {
sb.append(v).append("\n");
sb.append(" ").append(v).append("\n");
}
});
}
@ -173,8 +161,8 @@ public class MutableAnnotation implements Annotation {
return this;
}
public Span getSpan() {
return (getStart() == getEnd()) ? Span.instant : Span.interval;
public Temporal getTemporal() {
return (getStart() == getEnd()) ? Temporal.instant : Temporal.interval;
}
public String asJson() {

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.
@ -16,7 +16,7 @@
package io.nosqlbench.api.annotations;
public enum Span {
public enum Temporal {
/**
* A span of time of size zero.
*/

View File

@ -16,33 +16,65 @@
package io.nosqlbench.api.config;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Pattern;
public class MapLabels implements NBLabels {
private final Map<String,String> labels;
private String[] instanceFields = new String[0];
public MapLabels(final Map<String, String> labels) {
public MapLabels(final Map<String, String> labels, String... instanceFields) {
verifyValidNamesAndValues(labels);
// verifyValidValues(labels);
this.labels = Collections.unmodifiableMap(labels);
this.instanceFields = instanceFields;
}
public MapLabels(final Map<String,String> parentLabels, final Map<String,String> childLabels) {
final Map<String,String> combined = new LinkedHashMap<>();
parentLabels.forEach(combined::put);
public MapLabels(final Map<String,String> parentLabels, final Map<String,String> childLabels, String... instanceFields) {
final Map<String, String> combined = new LinkedHashMap<>(parentLabels);
childLabels.forEach((k,v) -> {
if (combined.containsKey(k))
throw new RuntimeException("Can't overlap label keys (for instance " + k + ") between parent and child elements. parent:" + parentLabels + ", child:" + childLabels);
combined.put(k,v);
});
verifyValidNamesAndValues(combined);
// verifyValidValues(combined);
this.instanceFields = instanceFields;
labels=Collections.unmodifiableMap(combined);
}
private final Pattern validNamesPattern = Pattern.compile("^[a-zA-Z_][a-zA-Z0-9_]+");
private void verifyValidNamesAndValues(Map<String, String> labels) {
labels.forEach((label,value) -> {
if (!validNamesPattern.matcher(label).matches()) {
throw new RuntimeException("Invalid label name '" + label + "', only a-z,A-Z,_ are allowed as the initial character, and a-z,A-Z,0-9,_ are allowed after.");
}
// if (!validNamesPattern.matcher(value).matches()) {
// throw new RuntimeException("Invalid label value '" + value + "', only a-z,A-Z,_ are allowed as the initial character, and a-z,A-Z,0-9,_ are allowed after.");
// }
});
}
private void verifyValidValues(Map<String, String> labels) {
for (String value : labels.values()) {
if (!validNamesPattern.matcher(value).matches()) {
throw new RuntimeException("Invalid label value '" + value + "', only a-z,A-Z,_ are allowed as the initial character, and a-z,A-Z,0-9,_ are allowed after.");
}
}
}
@Override
public String linearizeValues(final char delim, final String... included) {
final StringBuilder sb = new StringBuilder();
final List<String> includedNames = new ArrayList<>();
if (0 < included.length) Collections.addAll(includedNames, included);
else this.labels.keySet().forEach(includedNames::add);
else includedNames.addAll(this.labels.keySet());
for (String includedName : includedNames) {
final boolean optional= includedName.startsWith("[") && includedName.endsWith("]");
@ -65,7 +97,7 @@ public class MapLabels implements NBLabels {
final List<String> includedNames = new ArrayList<>();
if (0 < included.length) Collections.addAll(includedNames, included);
else this.labels.keySet().forEach(includedNames::add);
else includedNames.addAll(this.labels.keySet());
String rawName = null;
if (null != bareName) {
rawName = this.labels.get(bareName);
@ -92,14 +124,28 @@ public class MapLabels implements NBLabels {
}
@Override
public NBLabels and(final String... labelsAndValues) {
if (0 != (labelsAndValues.length % 2))
throw new RuntimeException("Must provide even number of keys and values: " + Arrays.toString(labelsAndValues));
final Map<String,String> childLabels = new LinkedHashMap<>();
for (int i = 0; i < labelsAndValues.length; i+=2) childLabels.put(labelsAndValues[i], labelsAndValues[i + 1]);
public MapLabels andTypes(final String... labelsAndValues) {
final Map<String, String> childLabels = getStringStringMap(labelsAndValues);
return new MapLabels(labels,childLabels);
}
@Override
public MapLabels and(NBLabels labels) {
return new MapLabels(this.labels,labels.asMap(), concat(this.instanceFields,labels.getInstanceFields()));
}
@Override
public MapLabels andInstances(final String... labelsAndValues) {
final Map<String, String> childLabels = getStringStringMap(labelsAndValues);
String[] childInstanceFields = getNamesArray(labelsAndValues);
return new MapLabels(this.labels,childLabels,concat(this.instanceFields,getNamesArray(labelsAndValues)));
}
@Override
public MapLabels andInstances(Map<String, String> instanceLabelsAndValues) {
return new MapLabels(this.labels,instanceLabelsAndValues,instanceLabelsAndValues.keySet().toArray(new String[0]));
}
@Override
public NBLabels modifyName(final String nameToModify, final Function<String, String> transform) {
if (!this.labels.containsKey(nameToModify))
@ -134,7 +180,7 @@ public class MapLabels implements NBLabels {
}
@Override
public String only(final String name) {
public String valueOf(final String name) {
if (!this.labels.containsKey(name))
throw new RuntimeException("The specified key does not exist: '" + name + '\'');
final String only = labels.get(name);
@ -148,7 +194,55 @@ public class MapLabels implements NBLabels {
}
@Override
public NBLabels and(final Map<String, String> moreLabels) {
public NBLabels onlyTypes() {
Map<String,String> typesOnlyMap = new LinkedHashMap<>(this.labels);
for (String instanceField : this.instanceFields) {
typesOnlyMap.remove(instanceField);
}
return new MapLabels(typesOnlyMap);
}
@Override
public NBLabels onlyInstances() {
Map<String,String> instancesOnlyMap = new LinkedHashMap<>();
for (String instanceField : this.instanceFields) {
instancesOnlyMap.put(instanceField,this.labels.get(instanceField));
}
return new MapLabels(instancesOnlyMap);
}
@Override
public String[] getInstanceFields() {
return instanceFields;
}
@Override
public NBLabels andTypes(final Map<String, String> moreLabels) {
return new MapLabels(this.labels, moreLabels);
}
private String[] concat(String[] a, String[] b) {
String[] c = new String[a.length+b.length];
System.arraycopy(a,0,c,0,a.length);
System.arraycopy(b,0,c,a.length,b.length);
return c;
}
private static String[] getNamesArray(final String... labelsAndValues) {
String[] keys = new String[labelsAndValues.length>>1];
for (int i = 0; i < keys.length; i++) {
keys[i]=labelsAndValues[i<<1];
}
return keys;
}
@NotNull
private static Map<String, String> getStringStringMap(String[] labelsAndValues) {
if (0 != (labelsAndValues.length % 2))
throw new RuntimeException("Must provide even number of keys and values: " + Arrays.toString(labelsAndValues));
final Map<String,String> childLabels = new LinkedHashMap<>();
for (int i = 0; i < labelsAndValues.length; i+=2) childLabels.put(labelsAndValues[i], labelsAndValues[i + 1]);
return childLabels;
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 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.api.config;
import io.nosqlbench.api.errors.BasicError;
import java.util.LinkedHashMap;
import java.util.Map;
public class NBLabelSpec {
public static NBLabels parseLabels(String labeldata) {
NBLabels buf = NBLabels.forKV();
Map<String, String> parsedLabels = new LinkedHashMap<>();
for (String component : labeldata.split("[,; ]+")) {
String[] parts = component.split("[:=]+", 2);
if (parts.length != 2) {
throw new BasicError("Unable to parse labels to set:" + labeldata);
}
if (parts[1].startsWith("#")) {
buf = buf.and(NBLabels.forKV().andInstances(parts[0], parts[1].substring(1)));
} else if (parts[1].startsWith("$")) {
buf = buf.and(NBLabels.forKV().andTypes(parts[0], parts[1].substring(1)));
} else {
if (parts[1].matches(".*[0-9]+.*")) {
throw new BasicError("You have specified an auxiliary tag which contains numbers in its value (" + component + "), but you have not designated it as a dimension, as in " + parts[0] + ":$" + parts[1] + " or an instance value, as in " + parts[0] + ":#" + parts[1]);
}
buf = buf.and(NBLabels.forKV().andTypes(parts[0], parts[1]));
}
}
return buf;
}
}

View File

@ -48,79 +48,4 @@ public interface NBLabeledElement extends NBComponent {
}
}
//
// NBLabeledElement EMPTY = forMap(Map.of());
//
// Map<String, String> getLabels();
//
// /**
// * TODO: Should throw an error when new keys are duplicated
// * @param keyvalues
// * @return
// */
// default Map<String, String> getLabelsAnd(final String... keyvalues) {
// final LinkedHashMap<String, String> map = new LinkedHashMap<>(this.getLabels());
// for (int idx = 0; idx < keyvalues.length; idx+=2) map.put(keyvalues[idx], keyvalues[idx + 1]);
// return map;
// }
//
//// default NBLabeledElement and(String... keyvalues) {
////
//// }
//
// default Map<String, String> getLabelsAnd(final Map<String,String> extra) {
// final LinkedHashMap<String,String> map = new LinkedHashMap<>(this.getLabels());
// map.putAll(extra);
// return map;
// }
//
// static MapLabels forMap(final Map<String,String> labels) {
// return new MapLabels(labels);
// }
//
// class MapLabels implements NBLabeledElement {
// private final Map<String, String> labels;
//
// public MapLabels(final Map<String,String> labels) {
// this.labels = labels;
// }
//
// @Override
// public Map<String, String> getLabels() {
// return this.labels;
// }
// }
//
// /**
// * Create a single String representation of the label set, preserving key order,
// * with optional additional labels, in the form of:
// * <pre>{@code
// * key1:value1,key2:value2,...
// * }</pre>
// * @param and
// * @return
// */
// default String linearizeLabels(final Map<String,String> and) {
// final StringBuilder sb= new StringBuilder();
// final Map<String, String> allLabels = getLabelsAnd(and);
// final ArrayList<String> sortedLabels = new ArrayList<>(allLabels.keySet());
// for (final String label : sortedLabels) sb.append(label).append(':').append(allLabels.get(label)).append(',');
// sb.setLength(sb.length()-",".length());
// return sb.toString();
// }
//
// /**
// * Equivalent to {@link #linearizeLabels(Map)}, except that additional key-value pairs can
// * be expressed as a pairs of Strings in the argument list.
// * @param and - An even numbered list of strings as key1, value1, key2, value2, ...
// * @return A linearized string representation
// */
// default String linearizeLabels(final String... and) {
// return this.linearizeLabels(this.getLabelsAnd(and));
// }
//
// default String linearizeLabelsByValueGraphite(final String... and) {
// return this.linearizeLabelsByValueDelim(".",and);
// }
//
}

View File

@ -131,27 +131,29 @@ public interface NBLabels {
* @param labelName The named label to modify
* @param transform A Lambda which will modify the existing value.
* @return A new NBLabels value, separate from the original
* @@throws RuntimeException if either the key is not found or the values is null.
* @throws RuntimeException if either the key is not found or the values is null.
*/
NBLabels modifyValue(String labelName, Function<String,String> transform);
/**
* Create a new NBLabels value with the additional keys and values appended.
*
* @param labelsAndValues
* @param typeLabelsAndValues
* Keys and values in "key1", "value1", "key2", "value2", ... form
* @return A new NBLabels instance
*/
NBLabels and(String... labelsAndValues);
NBLabels andTypes(String... typeLabelsAndValues);
NBLabels and(NBLabels labels);
/**
* Create a new NBLabels value with the additional keys and values appended.
*
* @param labels
* a map of keys and values
* @param typeLabelsAndValues a map of keys and values
* @return A new NBLabels instance
*/
NBLabels and(Map<String, String> labels);
NBLabels andTypes(Map<String, String> typeLabelsAndValues);
NBLabels andInstances(String... instanceLabelsAndValues);
NBLabels andInstances(Map<String,String> instanceLabelsAndValues);
/**
* Return the value of the specified label key.
@ -162,7 +164,7 @@ public interface NBLabels {
* @throws RuntimeException
* if the specified label does not exist in the set, or the value is null.
*/
String only(String name);
String valueOf(String name);
/**
* Return a map representation of the label set, regardless of the underlying form.
@ -170,4 +172,13 @@ public interface NBLabels {
* @return a {@link Map} of keys and values, in deterministic order
*/
Map<String, String> asMap();
/**
* @return a new set of labels which includes only those which are not using per-instance semantics.
*/
NBLabels onlyTypes();
NBLabels onlyInstances();
String[] getInstanceFields();
}

View File

@ -30,7 +30,6 @@ import java.io.File;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
@ -106,7 +105,8 @@ public class ActivityMetrics {
* @return the timer, perhaps a different one if it has already been registered
*/
public static Timer timer(NBLabeledElement parent, String metricFamilyName, int hdrdigits) {
final NBLabels labels = parent.getLabels().and("name",metricFamilyName);
final NBLabels labels = parent.getLabels().andTypes("name",sanitize(metricFamilyName));
Timer registeredTimer = (Timer) register(labels, () ->
new NBMetricTimer(labels,
@ -134,7 +134,7 @@ public class ActivityMetrics {
* @return the histogram, perhaps a different one if it has already been registered
*/
public static Histogram histogram(NBLabeledElement labeled, String metricFamilyName, int hdrdigits) {
final NBLabels labels = labeled.getLabels().and("name", metricFamilyName);
final NBLabels labels = labeled.getLabels().andTypes("name", sanitize(metricFamilyName));
return (Histogram) register(labels, () ->
new NBMetricHistogram(
labels,
@ -157,7 +157,7 @@ public class ActivityMetrics {
* @return the counter, perhaps a different one if it has already been registered
*/
public static Counter counter(NBLabeledElement parent, String metricFamilyName) {
final NBLabels labels = parent.getLabels().and("name",metricFamilyName);
final NBLabels labels = parent.getLabels().andTypes("name",metricFamilyName);
return (Counter) register(labels, () -> new NBMetricCounter(labels));
}
@ -173,7 +173,7 @@ public class ActivityMetrics {
* @return the meter, perhaps a different one if it has already been registered
*/
public static Meter meter(NBLabeledElement parent, String metricFamilyName) {
final NBLabels labels = parent.getLabels().and("name",metricFamilyName);
final NBLabels labels = parent.getLabels().andTypes("name",sanitize(metricFamilyName));
return (Meter) register(labels, () -> new NBMetricMeter(labels));
}
@ -191,7 +191,7 @@ public class ActivityMetrics {
@SuppressWarnings("unchecked")
public static <T> Gauge<T> gauge(NBLabeledElement parent, String metricFamilyName, Gauge<T> gauge) {
final NBLabels labels = parent.getLabels().and("name",metricFamilyName);
final NBLabels labels = parent.getLabels().andTypes("name",sanitize(metricFamilyName));
return (Gauge<T>) register(labels, () -> new NBMetricGauge(labels,gauge));
}
@ -342,4 +342,16 @@ public class ActivityMetrics {
.forEach(get()::remove);
}
public static String sanitize(String word) {
String sanitized = word;
sanitized = sanitized.replaceAll("\\..+$", "");
sanitized = sanitized.replaceAll("-","_");
sanitized = sanitized.replaceAll("[^a-zA-Z0-9_]+", "");
if (!word.equals(sanitized)) {
logger.warn("The identifier or value '" + word + "' was sanitized to '" + sanitized + "' to be compatible with monitoring systems. You should probably change this to make diagnostics easier.");
}
return sanitized;
}
}

View File

@ -19,6 +19,8 @@ package io.nosqlbench.api.engine.metrics.reporters;
import com.codahale.metrics.*;
import io.nosqlbench.api.config.NBLabeledElement;
import io.nosqlbench.api.config.NBLabels;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.Writer;
@ -34,8 +36,9 @@ import java.util.Map;
* exposition format</a>
*/
public enum PromExpositionFormat {
;
public class PromExpositionFormat {
private final static Logger logger = LogManager.getLogger("METRICS");
public static String format(final Clock clock, final Metric... metrics) {
return PromExpositionFormat.format(clock, new StringBuilder(), metrics).toString();
}
@ -64,7 +67,7 @@ public enum PromExpositionFormat {
if (metric instanceof final Counting counting) {
buffer.append("# TYPE ")
.append(labels.modifyValue("name", n -> n+"_total").only("name")).append(" counter\n");
.append(labels.modifyValue("name", n -> n+"_total").valueOf("name")).append(" counter\n");
final long count = counting.getCount();
buffer
@ -77,12 +80,12 @@ public enum PromExpositionFormat {
}
if (metric instanceof final Sampling sampling) {
// Use the summary form
buffer.append("# TYPE ").append(labels.only("name")).append(" summary\n");
buffer.append("# TYPE ").append(labels.valueOf("name")).append(" summary\n");
final Snapshot snapshot = sampling.getSnapshot();
for (final double quantile : new double[]{0.5, 0.75, 0.90, 0.95, 0.98, 0.99, 0.999}) {
final double value = snapshot.getValue(quantile);
buffer
.append(labels.and("quantile", String.valueOf(quantile)).linearize("name"))
.append(labels.andTypes("quantile", String.valueOf(quantile)).linearize("name"))
.append(' ')
.append(value)
.append('\n');
@ -92,25 +95,25 @@ public enum PromExpositionFormat {
.append(' ')
.append(snapshotCount)
.append('\n');
buffer.append("# TYPE ").append(labels.only("name")).append("_max").append(" gauge\n");
buffer.append("# TYPE ").append(labels.valueOf("name")).append("_max").append(" gauge\n");
final long maxValue = snapshot.getMax();
buffer.append(labels.modifyValue("name",n->n+"_max").linearize("name"))
.append(' ')
.append(maxValue)
.append('\n');
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_min").only("name")).append(" gauge\n");
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_min").valueOf("name")).append(" gauge\n");
final long minValue = snapshot.getMin();
buffer.append(labels.modifyValue("name",n->n+"_min").linearize("name"))
.append(' ')
.append(minValue)
.append('\n');
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_mean").only("name")).append(" gauge\n");
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_mean").valueOf("name")).append(" gauge\n");
final double meanValue = snapshot.getMean();
buffer.append(labels.modifyValue("name",n->n+"_mean").linearize("name"))
.append(' ')
.append(meanValue)
.append('\n');
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_stdev").only("name")).append(" gauge\n");
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_stdev").valueOf("name")).append(" gauge\n");
final double stdDev = snapshot.getStdDev();
buffer.append(labels.modifyValue("name",n->n+"_stdev").linearize("name"))
.append(' ')
@ -119,7 +122,7 @@ public enum PromExpositionFormat {
}
if (metric instanceof final Gauge gauge) {
buffer.append("# TYPE ").append(labels.only("name")).append(" gauge\n");
buffer.append("# TYPE ").append(labels.valueOf("name")).append(" gauge\n");
final Object value = gauge.getValue();
if (value instanceof final Number number) {
final double doubleValue = number.doubleValue();
@ -143,28 +146,28 @@ public enum PromExpositionFormat {
);
}
if (metric instanceof final Metered meter) {
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_1mRate").only("name")).append(" gauge\n");
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_1mRate").valueOf("name")).append(" gauge\n");
final double oneMinuteRate = meter.getOneMinuteRate();
buffer.append(labels.modifyValue("name",n->n+"_1mRate").linearize("name"))
.append(' ')
.append(oneMinuteRate)
.append('\n');
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_5mRate").only("name")).append(" gauge\n");
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_5mRate").valueOf("name")).append(" gauge\n");
final double fiveMinuteRate = meter.getFiveMinuteRate();
buffer.append(labels.modifyValue("name",n->n+"_5mRate").linearize("name"))
.append(' ')
.append(fiveMinuteRate)
.append('\n');
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_15mRate").only("name")).append(" gauge\n");
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_15mRate").valueOf("name")).append(" gauge\n");
final double fifteenMinuteRate = meter.getFifteenMinuteRate();
buffer.append(labels.modifyValue("name",n->n+"_15mRate").linearize("name"))
.append(' ')
.append(fifteenMinuteRate)
.append('\n');
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_meanRate").only("name")).append(" gauge\n");
buffer.append("# TYPE ").append(labels.modifyValue("name",n->n+"_meanRate").valueOf("name")).append(" gauge\n");
final double meanRate = meter.getMeanRate();
buffer.append(labels.modifyValue("name",n->n+"_meanRate").linearize("name"))
.append(' ')
@ -176,8 +179,6 @@ public enum PromExpositionFormat {
}
return buffer;
}
public static String labels(final Map<String, String> labels, final String... additional) {
@ -221,4 +222,16 @@ public enum PromExpositionFormat {
}
}
private static String sanitize(String word) {
String sanitized = word;
sanitized = sanitized.replaceAll("\\..+$", "");
sanitized = sanitized.replaceAll("-","_");
sanitized = sanitized.replaceAll("[^a-zA-Z0-9_]+", "");
if (!word.equals(sanitized)) {
logger.warn("The identifier or value '" + word + "' was sanitized to '" + sanitized + "' to be compatible with monitoring systems. You should probably change this to make diagnostics easier.");
}
return sanitized;
}
}

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

@ -0,0 +1,84 @@
/*
* Copyright (c) 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.api.system;
import io.nosqlbench.api.errors.BasicError;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class NBStatePath {
public static final String NB_STATEDIR_PATHS = "$NBSTATEDIR:$PWD/.nosqlbench:$HOME/.nosqlbench";
private static final List<String> statePathAccesses = new ArrayList<>();
private static Path statepath;
public static Path initialize() {
return initialize(NB_STATEDIR_PATHS);
}
public static Path initialize(String statedirs) {
if (statedirs==null || statedirs.isBlank()) {
statedirs = NB_STATEDIR_PATHS;
}
if (statepath!=null) {
return statepath;
}
if (0 < statePathAccesses.size())
throw new BasicError("The state dir must be set before it is used by other\n" +
" options. If you want to change the statedir, be sure you do it before\n" +
" dependent options. These parameters were called before this --statedir:\n" +
statePathAccesses.stream().map(s -> "> " + s).collect(Collectors.joining("\n")));
if (null != statepath) return statepath;
final List<String> paths = NBEnvironment.INSTANCE.interpolateEach(":", statedirs);
Path selected = null;
for (final String pathName : paths) {
final Path path = Path.of(pathName);
if (Files.exists(path)) {
if (Files.isDirectory(path)) {
selected = path;
break;
}
System.err.println("ERROR: possible state dir path is not a directory: '" + path + '\'');
}
}
if (null == selected) selected = Path.of(paths.get(paths.size() - 1));
if (!Files.exists(selected)) try {
Files.createDirectories(
selected,
PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwxrwx---"))
);
} catch (final IOException e) {
throw new BasicError("Could not create state directory at '" + selected + "': " + e.getMessage());
}
NBEnvironment.INSTANCE.put(NBEnvironment.NBSTATEDIR, selected.toString());
return selected;
}
}

View File

@ -21,14 +21,40 @@ import org.junit.jupiter.api.Test;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class MapLabelsTest {
@Test
public void testLinearizeValues() {
final MapLabels l1 = new MapLabels(Map.of("key-a", "value-a", "key-c", "value-c"));
final String result = l1.linearizeValues('_', "key-a", "[key-b]", "key-c");
assertThat(result).isEqualTo("value-a_value-c");
final MapLabels l1 = new MapLabels(Map.of("key_a", "value_a", "key_c", "value_c"));
final String result = l1.linearizeValues('_', "key_a", "[key_b]", "key_c");
assertThat(result).isEqualTo("value_a_value_c");
}
@Test
public void testInstances() {
final MapLabels l1 = new MapLabels(Map.of("key_a", "value_a", "key_c", "value_c"),"key_c");
NBLabels typesOnly = l1.onlyTypes();
assertThat(typesOnly.linearizeValues()).isEqualTo("value_a");
}
@Test
public void testInstanceCombination() {
final MapLabels l1 = new MapLabels(Map.of("key_a", "value_a"),Map.of("key_c", "value_c"),"key_c");
final MapLabels l2 = new MapLabels(Map.of("key_dog", "value_dog"),Map.of( "key_cat", "value_cat"),"key_dog");
final MapLabels l3 = l1.and(l2);
assertThat(l3.linearizeValues()).matches("value_a.value_c.value_dog.value_cat");
assertThat(l3.onlyTypes().linearizeValues()).matches("value_a.value_cat");
assertThat(l3.onlyInstances().linearizeValues()).matches("value_c.value_dog");
}
@Test
public void testInvalidCharacters() {
assertThatThrownBy(() -> new MapLabels(Map.of("a-b","c-d"))).isOfAnyClassIn(RuntimeException.class);
}
}

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

@ -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.
@ -18,6 +18,7 @@ package io.nosqlbench.nb.api.annotations;
import io.nosqlbench.api.annotations.Annotation;
import io.nosqlbench.api.annotations.Layer;
import io.nosqlbench.api.config.NBLabeledElement;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@ -30,36 +31,31 @@ public class AnnotationBuilderTest {
public void testBasicAnnotation() {
Annotation an1 = Annotation.newBuilder()
.session("test-session")
.element(NBLabeledElement.forKV("test_element","value"))
.at(time)
.layer(Layer.Scenario)
.label("labelka", "labelvb")
.label("labelkc", "labelvd")
.detail("detailk1", "detailv1")
.detail("detailk2", "detailv21\ndetailv22")
.detail("detailk3", "v1\nv2\nv3\n")
.build();
String represented = an1.toString();
assertThat(represented).isEqualTo("session: test-session\n" +
"[2020-09-13T12:26:40Z]\n" +
"span:instant\n" +
"details:\n" +
" detailk1: detailv1\n" +
" detailk2: \n" +
" detailv21\n" +
" detailv22\n" +
" detailk3: \n" +
" v1\n" +
" v2\n" +
" v3\n" +
"labels:\n" +
" layer: Scenario\n" +
" labelka: labelvb\n" +
" labelkc: labelvd\n" +
" session: test-session\n" +
" span: instant\n" +
" appname: nosqlbench\n");
assertThat(represented).isEqualTo(
"""
[2020-09-13T12:26:40Z]
span:instant
details:
detailk1: detailv1
detailk2:
detailv21
detailv22
detailk3:
v1
v2
v3
labels:
test_element: value
""");
}

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<Configuration status="debug" strict="true" name="XMLConfigTest">
<Filter type="ThresholdFilter" level="trace"/>
<Appenders>
<Appender type="Console" name="STDOUT">
<Layout type="PatternLayout" pattern="%7r %-5level [%t] %-12logger{0} %msg%n%throwable"/>
<Filters>
<Filter type="MarkerFilter" marker="FLOW" onMatch="DENY" onMismatch="NEUTRAL"/>
<Filter type="MarkerFilter" marker="EXCEPTION" onMatch="DENY" onMismatch="ACCEPT"/>
</Filters>
</Appender>
<Appender type="Console" name="FLOW">
<Layout type="PatternLayout" pattern="%C{1}.%M %m %ex%n"/><!-- class and line number -->
<Filters>
<Filter type="MarkerFilter" marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
<Filter type="MarkerFilter" marker="EXCEPTION" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
</Appender>
<Appender type="File" name="APPSLOG" fileName="docs/apps.log">
<Layout type="PatternLayout">
<Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
</Layout>
</Appender>
</Appenders>
<Loggers>
<Logger name="io.nosqlbench.docsys" level="info" additivity="false">
<AppenderRef ref="APPSLOG"/>
</Logger>
<Root level="trace">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>

View File

@ -158,7 +158,7 @@ public class ScriptExampleTests {
"logs/histostats.csv"));
String logdata = strings.stream().collect(Collectors.joining("\n"));
assertThat(logdata).contains("min,p25,p50,p75,p90,p95,");
assertThat(logdata.split("Tag=testhistostatslogger.cycles.servicetime,").length).isGreaterThanOrEqualTo(1);
assertThat(logdata.split("Tag=testhistostatslogger.cycles_servicetime,").length).isGreaterThanOrEqualTo(1);
}
@Test
@ -179,7 +179,7 @@ public class ScriptExampleTests {
List<String> strings = Files.readAllLines(Paths.get("hdrhistodata.log"));
String logdata = strings.stream().collect(Collectors.joining("\n"));
assertThat(logdata).contains(",HIST");
assertThat(logdata.split("Tag=testhistologger.cycles.servicetime,").length).isGreaterThanOrEqualTo(1);
assertThat(logdata.split("Tag=testhistologger.cycles_servicetime,").length).isGreaterThanOrEqualTo(1);
}
@Test
@ -241,8 +241,8 @@ public class ScriptExampleTests {
@Test
public void testReportedCoDelayStrict() {
ExecutionMetricsResult scenarioResult = runScenario("cocycledelay_strict");
assertThat(scenarioResult.getIOLog()).contains("step1 cycles.waittime=");
assertThat(scenarioResult.getIOLog()).contains("step2 cycles.waittime=");
assertThat(scenarioResult.getIOLog()).contains("step1 cycles_waittime=");
assertThat(scenarioResult.getIOLog()).contains("step2 cycles_waittime=");
String iolog = scenarioResult.getIOLog();
System.out.println(iolog);
// TODO: ensure that waittime is staying the same or increasing

View File

@ -31,13 +31,13 @@ for (i = 0; i < 5; i++) {
print("scenario exited prematurely, aborting.");
break;
}
print("backlogging, cycles=" + metrics.co_cycle_delay_bursty.cycles.servicetime.count +
" waittime=" + metrics.co_cycle_delay_bursty.cycles.waittime.value +
print("backlogging, cycles=" + metrics.co_cycle_delay_bursty.cycles_servicetime.count +
" waittime=" + metrics.co_cycle_delay_bursty.cycles_waittime.value +
" diagrate=" + activities.co_cycle_delay_bursty.diagrate +
" cyclerate=" + activities.co_cycle_delay_bursty.cyclerate
);
}
print('step1 metrics.waittime=' + metrics.co_cycle_delay_bursty.cycles.waittime.value);
print('step1 metrics.waittime=' + metrics.co_cycle_delay_bursty.cycles_waittime.value);
activities.co_cycle_delay_bursty.diagrate = "10000";
for (i = 0; i < 10; i++) {
@ -45,19 +45,19 @@ for (i = 0; i < 10; i++) {
print("scenario exited prematurely, aborting.");
break;
}
print("recovering, cycles=" + metrics.co_cycle_delay_bursty.cycles.servicetime.count +
" waittime=" + metrics.co_cycle_delay_bursty.cycles.waittime.value +
print("recovering, cycles=" + metrics.co_cycle_delay_bursty.cycles_servicetime.count +
" waittime=" + metrics.co_cycle_delay_bursty.cycles_waittime.value +
" diagrate=" + activities.co_cycle_delay_bursty.diagrate +
" cyclerate=" + activities.co_cycle_delay_bursty.cyclerate
);
scenario.waitMillis(1000);
if (metrics.co_cycle_delay_bursty.cycles.waittime.value < 50000000) {
if (metrics.co_cycle_delay_bursty.cycles_waittime.value < 50000000) {
print("waittime trended back down as expected, exiting on iteration " + i);
break;
}
}
//scenario.awaitActivity("co_cycle_delay");
print('step2 metrics.waittime=' + metrics.co_cycle_delay_bursty.cycles.waittime.value);
print('step2 metrics.waittime=' + metrics.co_cycle_delay_bursty.cycles_waittime.value);
scenario.stop(co_cycle_delay_bursty);
print("stopped activity co_cycle_delay_bursty");

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.
@ -26,18 +26,18 @@ co_cycle_delay = {
print('starting activity co_cycle_delay');
scenario.start(co_cycle_delay);
scenario.waitMillis(4000);
print('step1 cycles.waittime=' + metrics.co_cycle_delay.cycles.waittime.value);
print('step1 cycles_waittime=' + metrics.co_cycle_delay.cycles_waittime.value);
activities.co_cycle_delay.diagrate="10000";
for(i=0;i<5;i++) {
if (! scenario.isRunningActivity('co_cycle_delay')) {
print("scenario exited prematurely, aborting.");
break;
}
print("iteration " + i + " waittime now " + metrics.co_cycle_delay.cycles.waittime.value);
print("iteration " + i + " waittime now " + metrics.co_cycle_delay.cycles_waittime.value);
scenario.waitMillis(1000);
}
//scenario.awaitActivity("co_cycle_delay");
print('step2 cycles.waittime=' + metrics.co_cycle_delay.cycles.waittime.value);
print('step2 cycles_waittime=' + metrics.co_cycle_delay.cycles_waittime.value);
print("awaited activity");

View File

@ -1,6 +1,6 @@
/*
* 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.
@ -26,8 +26,8 @@ activitydef = {
scenario.run(activitydef);
print("current cycle = " + metrics.cycle_rate.cycles.servicetime.count);
print("mean cycle rate = " + metrics.cycle_rate.cycles.servicetime.meanRate);
print("current cycle = " + metrics.cycle_rate.cycles_servicetime.count);
print("mean cycle rate = " + metrics.cycle_rate.cycles_servicetime.meanRate);

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.
@ -34,13 +34,13 @@ print("measured cycle increment per second is expected to adjust to 1000");
print('cyclerate now:' + activities.cycle_rate_change.cyclerate);
var lastcount=metrics.cycle_rate_change.cycles.servicetime.count;
var lastcount=metrics.cycle_rate_change.cycles_servicetime.count;
for(i=0;i<20;i++) {
scenario.waitMillis(1000);
var nextcount=metrics.cycle_rate_change.cycles.servicetime.count;
var nextcount=metrics.cycle_rate_change.cycles_servicetime.count;
var cycles = (nextcount - lastcount);
print("new this second: " + (nextcount - lastcount));
print(" waittime: " + metrics.cycle_rate_change.cycles.waittime.value);
print(" waittime: " + metrics.cycle_rate_change.cycles_waittime.value);
lastcount=nextcount;
if (cycles>700 && cycles<1300) {
print("cycles adjusted, exiting on iteration " + i);

View File

@ -27,7 +27,7 @@ activitydef = {
scenario.start(activitydef);
scenario.waitMillis(500);
csvlogger.add(metrics.csvmetrics.cycles.servicetime);
csvlogger.add(metrics.csvmetrics.cycles_servicetime);
csvlogger.start(500,"MILLISECONDS");
scenario.waitMillis(2000);

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.
@ -26,10 +26,10 @@ activitydef = {
scenario.start(activitydef);
scenario.waitMillis(500);
while (metrics.testactivity.cycles.servicetime.count < 1000) {
print('waiting 10ms because cycles<10000 : ' + metrics.testactivity.cycles.servicetime.count);
while (metrics.testactivity.cycles_servicetime.count < 1000) {
print('waiting 10ms because cycles<10000 : ' + metrics.testactivity.cycles_servicetime.count);
scenario.waitMillis(10);
}
scenario.stop(activitydef);
print("count: " + metrics.testactivity.cycles.servicetime.count);
print("count: " + metrics.testactivity.cycles_servicetime.count);

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>