help system fixes

This commit is contained in:
Jonathan Shook 2024-10-07 16:24:32 -05:00
parent ed31d35886
commit b27177012e
23 changed files with 335 additions and 14 deletions

View File

@ -76,7 +76,7 @@ public class PromPushReporterComponent extends PeriodicTaskComponent {
.orElseThrow(() -> new RuntimeException("Unable to create path for apikey file: $NBSTATEDIR/prompush/prompush_apikey"));
if (Files.isRegularFile(keyfilePath)) {
try {
logger.info("Reading Bearer Token from {}", keyfilePath);
logger.debug(() -> "Reading Bearer Token from " + keyfilePath);
this.bearerToken = Files.readString(keyfilePath).trim();
} catch (IOException e) {
throw new RuntimeException(e);

View File

@ -20,6 +20,9 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.nosqlbench.adapters.api.activityconfig.rawyaml.RawOpsLoader;
import io.nosqlbench.engine.cmdstream.CmdType;
import io.nosqlbench.engine.cmdstream.NBJavaCommandLoader;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandInfo;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBHelpTopic;
import io.nosqlbench.nb.api.annotations.Annotation;
import io.nosqlbench.nb.api.annotations.Layer;
import io.nosqlbench.nb.api.apps.BundledApp;
@ -268,9 +271,13 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
}
if (options.getWantsListCommands()) {
for (CmdType value : CmdType.values()) {
System.out.println(value.name());
List<NBCommandInfo> commands = NBJavaCommandLoader.getCommands();
for (NBCommandInfo command : commands) {
System.out.println(
String.format("%-20s %s", command.getName(),command.getDescription())
);
}
return NBCLI.EXIT_OK;
}
if (options.wantsActivityTypes()) {
@ -369,6 +376,19 @@ public class NBCLI implements Function<String[], Integer>, NBLabeledElement {
}
if (options.wantsTopicalHelp()) {
String topic = options.wantsTopicalHelpFor();
Optional<? extends NBHelpTopic> infoFor = NBJavaCommandLoader.getInfoFor(topic);
// infoFor = infoFor.or(() -> MarkdownFinder.forHelpTopic(options.wantsTopicalHelpFor()));
infoFor.ifPresent(info -> {
System.out.print(info.getHelp());
});
if (infoFor.isPresent()) {
return NBCLI.EXIT_OK;
}
final Optional<String> helpDoc = MarkdownFinder.forHelpTopic(options.wantsTopicalHelpFor());
System.out.println(helpDoc.orElseThrow(
() -> new RuntimeException("No help could be found for " + options.wantsTopicalHelpFor())

View File

@ -704,6 +704,7 @@ public class NBCLIOptions {
this.cmdList.addAll(parsedCmds);
if (!arglist.isEmpty()) {
final String cmdParam = arglist.peekFirst();
Objects.requireNonNull(cmdParam);
final String helpmsg = """
@ -721,7 +722,14 @@ public class NBCLIOptions {
"""
.replaceAll("ARG", cmdParam)
.replaceAll("PROG", "nb5")
.replaceAll("INCLUDES", String.join(",", wantsIncludes()));
.replaceAll("INCLUDES", String.join(",", wantsIncludes()))
+ (arglist.size()>0 && arglist.peekFirst().startsWith("nb") ?
"""
(HINT:) It looks like you are starting your command with ARGV0
" which looks like the nb5 command itself. Maybe remove this?
""".replaceAll("ARGV0", arglist.peekFirst()) : ""
);
final String debugMessage = """
@ -731,6 +739,8 @@ public class NBCLIOptions {
"""
.replaceAll("COMMANDSTREAM",
String.join(" ", arglist));
if (consoleLevel.isGreaterOrEqualTo(NBLogLevel.INFO)) {
System.out.println(debugMessage);
}

View File

@ -21,16 +21,16 @@ import io.nosqlbench.nb.api.components.core.NBComponent;
import io.nosqlbench.engine.core.lifecycle.scenario.execution.NBCommandInfo;
import io.nosqlbench.nb.annotations.ServiceSelector;
import java.util.List;
import java.util.ServiceLoader;
import java.util.*;
import java.util.stream.Collectors;
public class NBJavaCommandLoader {
public static Class<? extends NBInvokableCommand> oneExists(String cmdName) {
ServiceLoader<NBCommandInfo> loader = ServiceLoader.load(NBCommandInfo.class);
ServiceSelector<NBCommandInfo> selector = ServiceSelector.of(cmdName, loader);
List<? extends ServiceLoader.Provider<? extends NBCommandInfo>> providers = selector.getAllProviders();
if (providers.size()>1) {
throw new RuntimeException("looking for an optional command for cmdName '" + cmdName +"' but found " + providers.size());
if (providers.size() > 1) {
throw new RuntimeException("looking for an optional command for cmdName '" + cmdName + "' but found " + providers.size());
}
if (!providers.isEmpty()) {
return providers.get(0).get().getType();
@ -51,4 +51,33 @@ public class NBJavaCommandLoader {
return selector;
}
public static List<NBCommandInfo> getCommands() {
ServiceLoader<NBCommandInfo> loader = ServiceLoader.load(NBCommandInfo.class);
LinkedList<NBCommandInfo> standards = new LinkedList<>();
LinkedList<NBCommandInfo> experimental = new LinkedList<>();
LinkedList<NBCommandInfo> diagnostic = new LinkedList<>();
List<NBCommandInfo> all = loader.stream().map(s -> s.get()).collect(Collectors.toCollection(LinkedList::new));
Collections.sort(all,Comparator.comparing(i -> i.getName()));
for (NBCommandInfo nbCommandInfo : all) {
String desc = nbCommandInfo.getDescription();
if (desc.startsWith("(diagnostic)")) {
diagnostic.add(nbCommandInfo);
} else if (desc.startsWith("(experimental)")) {
experimental.add(nbCommandInfo);
} else {
standards.add(nbCommandInfo);
}
}
standards.addAll(diagnostic);
standards.addAll(experimental);
return standards;
}
public static Optional<? extends NBCommandInfo> getInfoFor(String cmdName) {
return getSelector(cmdName).get();
}
}

View File

@ -27,6 +27,7 @@ import org.apache.logging.log4j.Logger;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.LinkedHashMap;
import java.util.Map;
@Service(value = NBBaseCommand.class, selector = "getenv")
@ -39,8 +40,16 @@ public class CMD_getenv extends NBBaseCommand {
@Override
public Object invoke(NBCommandParams params, PrintWriter stdout, PrintWriter stderr, Reader stdin, ContainerActivitiesController controller) {
String varname = params.maybeGet("var").orElseThrow(() -> new BasicError("The getenv command requires a variable named 'var' to be defined."));
String value = System.getenv(varname);
return Map.of(varname,value);
Map<String, String> got = new LinkedHashMap<>();
params.forEach((k, v) -> {
String value = System.getenv(v);
if (value == null) {
logger.warn(() -> "tried to get env var with name '" + v + "', but it was not defined");
} else {
got.put(k,value);
}
});
return got;
}
}

View File

@ -49,6 +49,7 @@ public class CMD_wait extends NBBaseCommand {
.map(l -> l * 1_000_000L)
.orElse(0L);
ns += params.maybeGet("us")
.or(() -> params.maybeGet("µs"))
.or(() -> params.maybeGet("micros"))
.map(Long::parseLong)
.map(l -> l * 1_000L)

View File

@ -26,4 +26,22 @@ public class INFO_await extends NBCommandInfo {
public Class<? extends NBInvokableCommand> getType() {
return CMD_await.class;
}
@Override
public String getHelp() {
return """
block the session thread until the named activity is no longer running
This means that the named activity is one of:
1. Not started yet (or ever)
2. Completed (having run all of its cycles)
3. Errored
4. Stopped by some other command
EXAMPLE:
await alias=myactivity
""";
}
}

View File

@ -26,4 +26,16 @@ public class INFO_example extends NBCommandInfo {
public Class<? extends NBInvokableCommand> getType() {
return CMD_example.class;
}
@Override
public String getHelp() {
return """
(diagnostic) a minimal implementation of a NoSQLBench command
This is a no-op command that does nothing and returns nothing
EXAMPLE:
example param1=does_not_matter
""";
}
}

View File

@ -26,4 +26,15 @@ public class INFO_forceStop extends NBCommandInfo {
public Class<? extends NBInvokableCommand> getType() {
return CMD_forceStop.class;
}
@Override
public String getHelp() {
return """
forces an activity to stop, interrupting it if necessary
EXAMPLE:
force_stop alias=going_down_now
""";
}
}

View File

@ -26,4 +26,21 @@ public class INFO_getenv extends NBCommandInfo {
public Class<? extends NBInvokableCommand> getType() {
return CMD_getenv.class;
}
@Override
public String getHelp() {
return """
hoist environment variables into the container state under the given names
EXAMPLE:
getenv authfile=AUTHFILE usermode=FOOSELECTED
This imports the AUTHFILE and FOOSELECTED environment variables into the container state
under the names authfile and usermode. The variables are then available to
other commands using the container state variable syntax, like ${stepname.authfile}
or ${stepname.usermode}
""";
}
}

View File

@ -26,4 +26,37 @@ public class INFO_run extends NBCommandInfo {
public Class<? extends NBInvokableCommand> getType() {
return CMD_run.class;
}
@Override
public String getHelp() {
return """
run an activity, blocking the main control thread until it is complete
Thorough documentation for these options can be found at:
https://docs.nosqlbench.io/user-guide/core-activity-params/
Essential parameters for this command are:
* driver (see --list-drivers to see what your runtime has built-in)
* workload a workload template in yaml, JSON, or Jsonnet form
* tags a set of filtering tags to enable or disable specific ops
* threads the number of concurrent requests to run
* cycles the total number of operations to run
* errors the error handling rules
Diagnostic Options
* dryrun enable dryrun diagnostics at different levels
Metrics Options
* alias name the activity so that you can observer or modify it concurrently
* instrument enable per-op-template metrics collection and reporting
* hdr_digits set the number of significant digits in histogram collection
Customization
* cyclerate set the ops/s for the activity
* rate synonym for cyclerate
* stride override the internal micro-batching step size (careful here)
* striderate set the rate for strides / second
* seq set the op sequencer to use
""";
}
}

View File

@ -26,4 +26,27 @@ public class INFO_start extends NBCommandInfo {
public Class<? extends NBInvokableCommand> getType() {
return CMD_start.class;
}
@Override
public String getHelp() {
return """
start an activity without blocking the main control thread
This is the asynchronous (with respect to the main control thread) version
of the run command. A NoSQLBench container can run arbitrary activities
concurrently, each within their own thread pool. By using the start
command, you can start them and then use other commands to observer,
modify, or block on state for additional testing stages.
By default, a NoSQLBench session (and all owned containers) will exit when
any of the following is true:
1. all session commands have completed
2. OR all activities have completed or failed
3. OR a command explicitly requests shutdown
EXAMPLE:
start alias=activity1 driver=stdout op="activity1: {{Identity()}}\n" cyclerate=10 cycles=600
start alias=activity2 driver=stdout op="activity2: {{Identity()}}\n" cyclerate=20 cycles=600
""";
}
}

View File

@ -26,4 +26,19 @@ public class INFO_stop extends NBCommandInfo {
public Class<? extends NBInvokableCommand> getType() {
return CMD_stop.class;
}
@Override
public String getHelp() {
return """
stop the named activity by requesting a graceful shutdown
This requests a shutdown of an activity which allows current operations
to finish before activity resources are closed according to native driver
conventions.
EXAMPLE:
stop alias=myactivity1
""";
}
}

View File

@ -26,4 +26,22 @@ public class INFO_wait extends NBCommandInfo {
public Class<? extends NBInvokableCommand> getType() {
return CMD_wait.class;
}
@Override
public String getHelp() {
return """
block the session thread for the specified amount of time
EXAMPLE:
# These all do the same thing
wait nanos=100000000
wait ns=100000000
wait micros=100000
wait us=100000
wait µs=100000
wait millis=100
wait ms=100
""";
}
}

View File

@ -34,9 +34,9 @@ public class CMD_ok extends NBBaseCommand {
@Override
public Object invoke(NBCommandParams params, PrintWriter stdout, PrintWriter stderr, Reader stdin, ContainerActivitiesController controller) {
stdout.write("Command '" + this.toString() + "' says OK and exits with no object or exception.");
stdout.write("Command '" + this.toString() + "' says OK and exits with the params it was given:\n");
for (String pkey : params.keySet()) {
stdout.println("diagnostic 'ok' command setting key '" + pkey + " to " + params.get(pkey));
stdout.println(" setting key '" + pkey + " to " + params.get(pkey));
}
return params;
}

View File

@ -26,4 +26,14 @@ public class INFO_error extends NBCommandInfo {
public Class<? extends NBInvokableCommand> getType() {
return CMD_error.class;
}
@Override
public String getHelp() {
return """
(diagnostic) throw an error with the provided params in the message
EXAMPLE:
error testing=testing123
""";
}
}

View File

@ -26,4 +26,16 @@ public class INFO_ok extends NBCommandInfo {
public Class<? extends NBInvokableCommand> getType() {
return CMD_ok.class;
}
@Override
public String getHelp() {
return """
(diagnostic) print and return the given parameters
EXAMPLE:
ok showme_this_varname=has_this_value
""";
}
}

View File

@ -17,6 +17,7 @@
package io.nosqlbench.engine.core.lifecycle.scenario.execution;
import io.nosqlbench.engine.core.lifecycle.scenario.container.NBBufferedContainer;
import io.nosqlbench.nb.annotations.Service;
import io.nosqlbench.nb.api.components.core.NBComponent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -31,9 +32,12 @@ import java.lang.reflect.InvocationTargetException;
* @Service(value = NBCommandInfo.class, selector = "<cmdname>")
* }</pre>
*/
public abstract class NBCommandInfo {
public abstract class NBCommandInfo implements NBHelpTopic {
private final static Logger logger = LogManager.getLogger(NBCommandInfo.class);
public abstract Class<? extends NBInvokableCommand> getType();
public NBInvokableCommand create(NBComponent parent, String cmdName, String ctxName) {
Constructor<? extends NBInvokableCommand> cmdCtor;
try {
@ -43,4 +47,15 @@ public abstract class NBCommandInfo {
throw new RuntimeException("Unable to instantiate command via ctor(parent,name,ctx): " + e + (e.getCause()!=null ? "cause: " + e.getCause().toString() : ""),e);
}
}
public String getName() {
Service service = this.getClass().getAnnotation(Service.class);
if (service==null) {
throw new RuntimeException("NBCommandInfo types must have Service annotations.");
}
return service.selector();
}
@Override
public abstract String getHelp();
}

View File

@ -0,0 +1,29 @@
package io.nosqlbench.engine.core.lifecycle.scenario.execution;
/*
* Copyright (c) 2022 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.
*/
public interface NBHelpTopic {
String getName();
default String getDescription() {
return getHelp().split("\n")[0];
}
String getHelp();
}

View File

@ -26,4 +26,18 @@ public class INFO_optimize extends NBCommandInfo {
public Class<? extends NBBaseCommand> getType() {
return CMD_optimize.class;
}
@Override
public String getHelp() {
return """
(experimental) invoke the multi-variate optimizer on a running activity under the given name
EXAMPLE:
# start alias=activity1 ...
optimize activity=activity1 planner=ratchet
This is experimental
""";
}
}

View File

@ -27,4 +27,13 @@ public class INFO_reset extends NBCommandInfo {
public Class<? extends NBInvokableCommand> getType() {
return CMD_reset.class;
}
@Override
public String getHelp() {
return """
(experimental) restart the initial step activity in a container after optimization
results have been determined by the previous steps
""";
}
}

View File

@ -26,4 +26,12 @@ public class NBFindmaxInfo extends NBCommandInfo {
public Class<? extends NBBaseCommand> getType() {
return CMD_findmax.class;
}
@Override
public String getHelp() {
return """
(experimental) invoke the findmax optimizer on a running activity
""";
}
}

View File

@ -26,4 +26,12 @@ public class NBOptimoInfo extends NBCommandInfo {
public Class<? extends NBBaseCommand> getType() {
return CMD_optimo.class;
}
@Override
public String getHelp() {
return """
(experimental) invoke the optimo multi-variate optimizer on a running activity
""";
}
}