Files
nosqlbench/engine-cli/src/main/java/io/nosqlbench/engine/cli/NBCLIOptions.java

961 lines
38 KiB
Java

/*
* Copyright (c) 2022-2023 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.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.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.nio.file.Path;
import java.security.InvalidParameterException;
import java.util.*;
import java.util.stream.Collectors;
/**
* No CLI parser lib is useful for command structures, it seems. So we have this instead, which is
* good enough. If something better is needed later, this can be replaced.
*/
public class NBCLIOptions {
// private final static Logger logger = LogManager.getLogger("OPTIONS");
private static final String NB_STATE_DIR = "--statedir";
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 String METRICS_PREFIX = "--metrics-prefix";
private static final String ANNOTATE_EVENTS = "--annotate";
private static final String ANNOTATORS_CONFIG = "--annotators";
// Enabled if the TERM env var is provided
private static final String ANSI = "--ansi";
private static final String DEFAULT_CHART_HDR_LOG_NAME = "hdrdata-for-chart.log";
// Discovery
private static final String HELP = "--help";
private static final String LIST_COMMANDS = "--list-commands";
private static final String LIST_METRICS = "--list-metrics";
private static final String LIST_DRIVERS = "--list-drivers";
private static final String LIST_ACTIVITY_TYPES = "--list-activity-types";
private static final String LIST_SCRIPTS = "--list-scripts";
private static final String LIST_WORKLOADS = "--list-workloads";
private static final String LIST_SCENARIOS = "--list-scenarios";
private static final String LIST_INPUT_TYPES = "--list-input-types";
private static final String LIST_OUTPUT_TYPES = "--list-output-types";
private static final String LIST_APPS = "--list-apps";
private static final String VERSION_COORDS = "--version-coords";
private static final String VERSION = "--version";
private static final String SHOW_SCRIPT = "--show-script";
private static final String COMPILE_SCRIPT = "--compile-script";
private static final String SCRIPT_FILE = "--script-file";
private static final String COPY = "--copy";
private static final String SHOW_STACKTRACES = "--show-stacktraces";
private static final String EXPERIMENTAL = "--experimental";
private static final String MATURITY = "--maturity";
private static final String SET_LABELS = "--set-labels";
private static final String ADD_LABELS = "--add-labels";
// Execution
private static final String EXPORT_CYCLE_LOG = "--export-cycle-log";
private static final String IMPORT_CYCLE_LOG = "--import-cycle-log";
private static final String HDR_DIGITS = "--hdr-digits";
// Execution Options
private static final String SESSION_NAME = "--session-name";
private static final String LOGS_DIR = "--logs-dir";
private static final String WORKSPACES_DIR = "--workspaces-dir";
private static final String LOGS_MAX = "--logs-max";
private static final String LOGS_LEVEL = "--logs-level";
private static final String DASH_V_INFO = "-v";
private static final String DASH_VV_DEBUG = "-vv";
private static final String DASH_VVV_TRACE = "-vvv";
private static final String REPORT_INTERVAL = "--report-interval";
private static final String REPORT_GRAPHITE_TO = "--report-graphite-to";
private static final String REPORT_PROMPUSH_TO = "--report-prompush-to";
private static final String GRAPHITE_LOG_LEVEL = "--graphite-log-level";
private static final String REPORT_CSV_TO = "--report-csv-to";
private static final String REPORT_SUMMARY_TO = "--report-summary-to";
private static final String REPORT_SUMMARY_TO_DEFAULT = "stdout:60,_LOGS_/_SESSION_.summary";
private static final String PROGRESS = "--progress";
private static final String WITH_LOGGING_PATTERN = "--with-logging-pattern";
private static final String LOGGING_PATTERN = "--logging-pattern";
private static final String CONSOLE_PATTERN = "--console-pattern";
private static final String LOGFILE_PATTERN = "--logfile-pattern";
private static final String LOG_HISTOGRAMS = "--log-histograms";
private static final String LOG_HISTOSTATS = "--log-histostats";
private static final String CLASSIC_HISTOGRAMS = "--classic-histograms";
private static final String LOG_LEVEL_OVERRIDE = "--log-level-override";
private static final String ENABLE_CHART = "--enable-chart";
private static final String DOCKER_METRICS = "--docker-metrics";
private static final String DOCKER_METRICS_AT = "--docker-metrics-at";
private static final String DOCKER_GRAFANA_TAG = "--docker-grafana-tag";
private static final String DOCKER_PROM_TAG = "--docker-prom-tag";
private static final String DOCKER_PROM_RETENTION_DAYS = "--docker-prom-retention-days";
private static final String GRAALJS_ENGINE = "--graaljs";
private static final String DEFAULT_CONSOLE_PATTERN = "TERSE";
private static final String DEFAULT_LOGFILE_PATTERN = "VERBOSE";
private final static String ENABLE_DEDICATED_VERIFICATION_LOGGER = "--enable-dedicated-verification-logging";
// private static final String DEFAULT_CONSOLE_LOGGING_PATTERN = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n";
private NBLabels labels = NBLabels.forKV();
private final List<Cmd> cmdList = new ArrayList<>();
private int logsMax;
private boolean wantsVersionShort;
private boolean wantsVersionCoords;
private boolean wantsActivityHelp;
private String wantsActivityHelpFor;
private boolean wantsActivityTypes;
private boolean wantsBasicHelp;
private String reportGraphiteTo;
private String reportPromPushTo;
private String reportCsvTo;
private int reportInterval = 10;
private String metricsPrefix = "nosqlbench";
private String wantsMetricsForActivity;
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<>();
private final List<String> statsLoggerConfigs = new ArrayList<>();
private final List<String> classicHistoConfigs = new ArrayList<>();
private String progressSpec = "console:1m";
private String logsDirectory = "logs";
private String workspacesDirectory = "workspaces";
private boolean wantsInputTypes;
private boolean wantsMarkerTypes;
private String[] rleDumpOptions = new String[0];
private String[] cyclelogImportOptions = new String[0];
private String consoleLoggingPattern = NBCLIOptions.DEFAULT_CONSOLE_PATTERN;
private String logfileLoggingPattern = NBCLIOptions.DEFAULT_LOGFILE_PATTERN;
private NBLogLevel logsLevel = NBLogLevel.INFO;
private Map<String, String> logLevelsOverrides = new HashMap<>();
private boolean enableChart;
private boolean dockerMetrics;
private boolean wantsListScenarios;
private boolean wantsListScripts;
private String wantsToCopyWorkload;
private boolean wantsWorkloadsList;
private final List<String> wantsToIncludePaths = new ArrayList<>();
private Engine engine = Engine.Graalvm;
private int hdr_digits = 3;
private String docker_grafana_tag = "7.3.4";
private String docker_prom_tag = "latest";
private boolean showStackTraces;
private boolean compileScript;
private String scriptFile;
private String[] annotateEvents = {"ALL"};
private String dockerMetricsHost;
private String annotatorsConfig = "";
private String statedirs = NBStatePath.NB_STATEDIR_PATHS;
private Path statepath;
private final String hdrForChartFileName = NBCLIOptions.DEFAULT_CHART_HDR_LOG_NAME;
private String dockerPromRetentionDays = "3650d";
private String reportSummaryTo = NBCLIOptions.REPORT_SUMMARY_TO_DEFAULT;
private boolean enableAnsi = (null != System.getenv("TERM")) && !System.getenv("TERM").isEmpty();
private Maturity minMaturity = Maturity.Unspecified;
private String graphitelogLevel = "info";
private boolean wantsListCommands;
private boolean wantsListApps;
private boolean dedicatedVerificationLogger;
public boolean isWantsListApps() {
return this.wantsListApps;
}
public boolean getWantsListCommands() {
return this.wantsListCommands;
}
public String getAnnotatorsConfig() {
return this.annotatorsConfig;
}
public NBLabels getLabelMap() {
return this.labels;
}
public String getChartHdrFileName() {
return this.hdrForChartFileName;
}
public String getDockerPromRetentionDays() {
return dockerPromRetentionDays;
}
public String getReportSummaryTo() {
return this.reportSummaryTo;
}
public void setWantsStackTraces(final boolean wantsStackTraces) {
showStackTraces = wantsStackTraces;
}
public boolean isEnableAnsi() {
return this.enableAnsi;
}
public String getLogfileLoggingPattern() {
return this.logfileLoggingPattern;
}
public String getGraphiteLogLevel() {
return graphitelogLevel;
}
public boolean isDedicatedVerificationLogger() {
return this.dedicatedVerificationLogger;
}
public void enableDedicatedVerificationLogger() {
this.dedicatedVerificationLogger = true;
}
public enum Mode {
ParseGlobalsOnly,
ParseAllOptions
}
public NBCLIOptions(final String[] args) {
this(args, Mode.ParseAllOptions);
}
public NBCLIOptions(final String[] args, final Mode mode) {
switch (mode) {
case ParseGlobalsOnly:
this.parseGlobalOptions(args);
break;
case ParseAllOptions:
this.parseAllOptions(args);
break;
}
}
private LinkedList<String> parseGlobalOptions(final String[] args) {
LinkedList<String> arglist = new LinkedList<>(Arrays.asList(args));
if (null == arglist.peekFirst()) {
this.wantsBasicHelp = true;
return arglist;
}
// Process --include and --statedir, separately first
// regardless of position
LinkedList<String> nonincludes = new LinkedList<>();
while (null != arglist.peekFirst()) {
final String word = arglist.peekFirst();
if (word.startsWith("--") && word.contains("=")) {
final String wordToSplit = arglist.removeFirst();
final String[] split = wordToSplit.split("=", 2);
arglist.offerFirst(split[1]);
arglist.offerFirst(split[0]);
continue;
}
switch (word) {
case NBCLIOptions.NB_STATE_DIR:
arglist.removeFirst();
statedirs = this.readWordOrThrow(arglist, "nosqlbench global state directory");
break;
case NBCLIOptions.INCLUDE:
arglist.removeFirst();
final String include = this.readWordOrThrow(arglist, "path to include");
this.wantsToIncludePaths.add(include);
break;
default:
nonincludes.addLast(arglist.removeFirst());
}
}
this.statepath = NBStatePath.initialize(statedirs);
arglist = nonincludes;
nonincludes = new LinkedList<>();
// Now that statdirs is settled, auto load argsfile if it is present
final NBCLIArgsFile argsfile = new NBCLIArgsFile();
argsfile.reserved(NBCLICommandParser.RESERVED_WORDS);
argsfile.preload("--argsfile-optional", NBCLIOptions.ARGS_FILE_DEFAULT);
arglist = argsfile.process(arglist);
// Parse all --argsfile... and other high level options
while (null != arglist.peekFirst()) {
final String word = arglist.peekFirst();
if (word.startsWith("--") && word.contains("=")) {
final String wordToSplit = arglist.removeFirst();
final String[] split = wordToSplit.split("=", 2);
arglist.offerFirst(split[1]);
arglist.offerFirst(split[0]);
continue;
}
switch (word) {
// These options modify other options. They should be processed early.
case NBCLIArgsFile.ARGS_FILE:
case NBCLIArgsFile.ARGS_FILE_OPTIONAL:
case NBCLIArgsFile.ARGS_FILE_REQUIRED:
case NBCLIArgsFile.ARGS_PIN:
case NBCLIArgsFile.ARGS_UNPIN:
this.statepath = NBStatePath.initialize(statedirs);
arglist = argsfile.process(arglist);
break;
case NBCLIOptions.ANSI:
arglist.removeFirst();
final String doEnableAnsi = this.readWordOrThrow(arglist, "enable/disable ansi codes");
this.enableAnsi = doEnableAnsi.toLowerCase(Locale.ROOT).matches("enabled|enable|true");
break;
case NBCLIOptions.DASH_V_INFO:
this.consoleLevel = NBLogLevel.INFO;
arglist.removeFirst();
break;
case NBCLIOptions.DASH_VV_DEBUG:
this.consoleLevel = NBLogLevel.DEBUG;
showStackTraces = true;
arglist.removeFirst();
break;
case NBCLIOptions.DASH_VVV_TRACE:
this.consoleLevel = NBLogLevel.TRACE;
showStackTraces = true;
arglist.removeFirst();
break;
case NBCLIOptions.ENABLE_DEDICATED_VERIFICATION_LOGGER:
enableDedicatedVerificationLogger();
arglist.removeFirst();
break;
case NBCLIOptions.ANNOTATE_EVENTS:
arglist.removeFirst();
final String toAnnotate = this.readWordOrThrow(arglist, "annotated events");
this.annotateEvents = toAnnotate.split("\\\\s*,\\\\s*");
break;
case NBCLIOptions.ANNOTATORS_CONFIG:
arglist.removeFirst();
annotatorsConfig = this.readWordOrThrow(arglist, "annotators config");
break;
case NBCLIOptions.REPORT_GRAPHITE_TO:
arglist.removeFirst();
this.reportGraphiteTo = arglist.removeFirst();
break;
case NBCLIOptions.REPORT_PROMPUSH_TO:
arglist.removeFirst();
this.reportPromPushTo = arglist.removeFirst();
break;
case NBCLIOptions.GRAPHITE_LOG_LEVEL:
arglist.removeFirst();
this.graphitelogLevel = arglist.removeFirst();
break;
case NBCLIOptions.METRICS_PREFIX:
arglist.removeFirst();
this.metricsPrefix = arglist.removeFirst();
break;
case NBCLIOptions.WORKSPACES_DIR:
arglist.removeFirst();
this.workspacesDirectory = this.readWordOrThrow(arglist, "a workspaces directory");
break;
case NBCLIOptions.DOCKER_PROM_TAG:
arglist.removeFirst();
this.docker_prom_tag = this.readWordOrThrow(arglist, "prometheus docker tag");
break;
case NBCLIOptions.DOCKER_PROM_RETENTION_DAYS:
arglist.removeFirst();
this.dockerPromRetentionDays = this.readWordOrThrow(arglist, "prometheus retention (3650d by default)");
break;
case NBCLIOptions.DOCKER_GRAFANA_TAG:
arglist.removeFirst();
this.docker_grafana_tag = this.readWordOrThrow(arglist, "grafana docker tag");
break;
case NBCLIOptions.VERSION:
arglist.removeFirst();
this.wantsVersionShort = true;
break;
case NBCLIOptions.VERSION_COORDS:
arglist.removeFirst();
this.wantsVersionCoords = true;
break;
case NBCLIOptions.DOCKER_METRICS_AT:
arglist.removeFirst();
this.dockerMetricsHost = this.readWordOrThrow(arglist, "docker metrics host");
break;
case NBCLIOptions.DOCKER_METRICS:
arglist.removeFirst();
this.dockerMetrics = true;
break;
case NBCLIOptions.SESSION_NAME:
arglist.removeFirst();
this.sessionName = this.readWordOrThrow(arglist, "a session name");
break;
case NBCLIOptions.LOGS_DIR:
arglist.removeFirst();
this.logsDirectory = this.readWordOrThrow(arglist, "a log directory");
break;
case NBCLIOptions.LOGS_MAX:
arglist.removeFirst();
this.logsMax = Integer.parseInt(this.readWordOrThrow(arglist, "max logfiles to keep"));
break;
case NBCLIOptions.LOGS_LEVEL:
arglist.removeFirst();
final String loglevel = this.readWordOrThrow(arglist, "a log level");
logsLevel = NBLogLevel.valueOfName(loglevel);
break;
case NBCLIOptions.LOG_LEVEL_OVERRIDE:
arglist.removeFirst();
this.logLevelsOverrides = this.parseLogLevelOverrides(this.readWordOrThrow(arglist, "log levels in name:LEVEL,... format"));
break;
case NBCLIOptions.CONSOLE_PATTERN:
arglist.removeFirst();
this.consoleLoggingPattern = this.readWordOrThrow(arglist, "console pattern");
break;
case NBCLIOptions.LOGFILE_PATTERN:
arglist.removeFirst();
this.logfileLoggingPattern = this.readWordOrThrow(arglist, "logfile pattern");
break;
case NBCLIOptions.WITH_LOGGING_PATTERN:
case NBCLIOptions.LOGGING_PATTERN:
arglist.removeFirst();
final String pattern = this.readWordOrThrow(arglist, "console and logfile pattern");
this.consoleLoggingPattern = pattern;
this.logfileLoggingPattern = pattern;
break;
case NBCLIOptions.SHOW_STACKTRACES:
arglist.removeFirst();
this.showStackTraces = true;
break;
case NBCLIOptions.EXPERIMENTAL:
arglist.removeFirst();
arglist.addFirst("experimental");
arglist.addFirst("--maturity");
break;
case NBCLIOptions.MATURITY:
arglist.removeFirst();
final String maturity = this.readWordOrThrow(arglist, "maturity of components to allow");
minMaturity = Maturity.valueOf(maturity.toLowerCase(Locale.ROOT));
case NBCLIOptions.SET_LABELS:
arglist.removeFirst();
String setLabelData = arglist.removeFirst();
setLabels(setLabelData);
break;
case NBCLIOptions.ADD_LABELS:
arglist.removeFirst();
String addLabeldata = arglist.removeFirst();
addLabels(addLabeldata);
break;
default:
nonincludes.addLast(arglist.removeFirst());
}
}
return nonincludes;
}
private void setLabels(String labeldata) {
this.labels = NBLabels.forKV();
addLabels(labeldata);
}
private void addLabels(String labeldata) {
NBLabels newLabels = NBLabelSpec.parseLabels(labeldata);
this.labels = this.labels.and(newLabels);
}
private void parseAllOptions(final String[] args) {
LinkedList<String> arglist = this.parseGlobalOptions(args);
final PathCanonicalizer canonicalizer = new PathCanonicalizer(this.wantsIncludes());
final LinkedList<String> nonincludes = new LinkedList<>();
while (null != arglist.peekFirst()) {
final String word = arglist.peekFirst();
switch (word) {
case NBCLIOptions.GRAALJS_ENGINE:
this.engine = Engine.Graalvm;
arglist.removeFirst();
break;
case NBCLIOptions.COMPILE_SCRIPT:
arglist.removeFirst();
this.compileScript = true;
break;
case NBCLIOptions.SHOW_SCRIPT:
arglist.removeFirst();
this.showScript = true;
break;
case NBCLIOptions.LIST_COMMANDS:
arglist.removeFirst();
wantsListCommands = true;
break;
case NBCLIOptions.LIST_METRICS:
arglist.removeFirst();
arglist.addFirst("start");
final Cmd cmd = Cmd.parseArg(arglist, canonicalizer);
this.wantsMetricsForActivity = cmd.getArg("driver");
break;
case NBCLIOptions.HDR_DIGITS:
arglist.removeFirst();
this.hdr_digits = Integer.parseInt(this.readWordOrThrow(arglist, "significant digits"));
break;
case NBCLIOptions.PROGRESS:
arglist.removeFirst();
this.progressSpec = this.readWordOrThrow(arglist, "a progress indicator, like 'log:1m' or 'screen:10s', or just 'log' or 'screen'");
break;
case NBCLIOptions.ENABLE_CHART:
arglist.removeFirst();
this.enableChart = true;
break;
case NBCLIOptions.HELP:
case "-h":
case "help":
arglist.removeFirst();
if (null == arglist.peekFirst()) this.wantsBasicHelp = true;
else {
this.wantsActivityHelp = true;
this.wantsActivityHelpFor = this.readWordOrThrow(arglist, "topic");
}
break;
case NBCLIOptions.EXPORT_CYCLE_LOG:
arglist.removeFirst();
this.rleDumpOptions = this.readAllWords(arglist);
break;
case NBCLIOptions.IMPORT_CYCLE_LOG:
arglist.removeFirst();
this.cyclelogImportOptions = this.readAllWords(arglist);
break;
case NBCLIOptions.LOG_HISTOGRAMS:
arglist.removeFirst();
final String logto = arglist.removeFirst();
this.histoLoggerConfigs.add(logto);
break;
case NBCLIOptions.LOG_HISTOSTATS:
arglist.removeFirst();
final String logStatsTo = arglist.removeFirst();
this.statsLoggerConfigs.add(logStatsTo);
break;
case NBCLIOptions.CLASSIC_HISTOGRAMS:
arglist.removeFirst();
final String classicHistos = arglist.removeFirst();
this.classicHistoConfigs.add(classicHistos);
break;
case NBCLIOptions.REPORT_INTERVAL:
arglist.removeFirst();
this.reportInterval = Integer.parseInt(this.readWordOrThrow(arglist, "report interval"));
break;
case NBCLIOptions.REPORT_CSV_TO:
arglist.removeFirst();
this.reportCsvTo = arglist.removeFirst();
break;
case NBCLIOptions.REPORT_SUMMARY_TO:
arglist.removeFirst();
this.reportSummaryTo = this.readWordOrThrow(arglist, "report summary file");
break;
case NBCLIOptions.LIST_DRIVERS:
case NBCLIOptions.LIST_ACTIVITY_TYPES:
arglist.removeFirst();
this.wantsActivityTypes = true;
break;
case NBCLIOptions.LIST_INPUT_TYPES:
arglist.removeFirst();
this.wantsInputTypes = true;
break;
case NBCLIOptions.LIST_OUTPUT_TYPES:
arglist.removeFirst();
this.wantsMarkerTypes = true;
break;
case NBCLIOptions.LIST_SCENARIOS:
arglist.removeFirst();
this.wantsListScenarios = true;
break;
case NBCLIOptions.LIST_SCRIPTS:
arglist.removeFirst();
this.wantsListScripts = true;
break;
case NBCLIOptions.LIST_WORKLOADS:
arglist.removeFirst();
this.wantsWorkloadsList = true;
break;
case NBCLIOptions.LIST_APPS:
arglist.removeFirst();
this.wantsListApps = true;
break;
case NBCLIOptions.SCRIPT_FILE:
arglist.removeFirst();
this.scriptFile = this.readWordOrThrow(arglist, "script file");
break;
case NBCLIOptions.COPY:
arglist.removeFirst();
this.wantsToCopyWorkload = this.readWordOrThrow(arglist, "workload to copy");
break;
default:
nonincludes.addLast(arglist.removeFirst());
}
}
arglist = nonincludes;
final Optional<List<Cmd>> commands = NBCLICommandParser.parse(arglist);
if (commands.isPresent()) cmdList.addAll(commands.get());
else {
final String arg = arglist.peekFirst();
Objects.requireNonNull(arg);
final String helpmsg = """
Could not recognize command 'ARG'.
This means that all of the following searches for a compatible command failed:
1. commands: no scenario command named 'ARG' is known. (start, run, await, ...)
2. scripts: no auto script named './scripts/auto/ARG.js' in the local filesystem.
3. scripts: no auto script named 'scripts/auto/ARG.js' was found in the PROG binary.
4. workloads: no workload file named ARG[.yaml] was found in the local filesystem, even in include paths INCLUDES.
5. workloads: no workload file named ARG[.yaml] was bundled in PROG binary, even in include paths INCLUDES.
6. apps: no application named ARG was bundled in PROG.
You can discover available ways to invoke PROG by using the various --list-* commands:
[ --list-commands, --list-scripts, --list-workloads (and --list-scenarios), --list-apps ]
"""
.replaceAll("ARG", arg)
.replaceAll("PROG", "nb5")
.replaceAll("INCLUDES", String.join(",", wantsIncludes()));
throw new BasicError(helpmsg);
}
}
public String[] wantsIncludes() {
return this.wantsToIncludePaths.toArray(new String[0]);
}
private Map<String, String> parseLogLevelOverrides(final String levelsSpec) {
final Map<String, String> levels = new HashMap<>();
Arrays.stream(levelsSpec.split("[,;]")).forEach(kp -> {
final String[] ll = kp.split(":");
if (2 != ll.length) throw new RuntimeException("Log level must have name:level format");
levels.put(ll[0], ll[1]);
});
return levels;
}
public Engine getScriptingEngine() {
return this.engine;
}
public List<LoggerConfigData> getHistoLoggerConfigs() {
final List<LoggerConfigData> configs =
this.histoLoggerConfigs.stream().map(LoggerConfigData::new).collect(Collectors.toList());
this.checkLoggerConfigs(configs, NBCLIOptions.LOG_HISTOGRAMS);
return configs;
}
public List<LoggerConfigData> getStatsLoggerConfigs() {
final List<LoggerConfigData> configs =
this.statsLoggerConfigs.stream().map(LoggerConfigData::new).collect(Collectors.toList());
this.checkLoggerConfigs(configs, NBCLIOptions.LOG_HISTOSTATS);
return configs;
}
public List<LoggerConfigData> getClassicHistoConfigs() {
final List<LoggerConfigData> configs =
this.classicHistoConfigs.stream().map(LoggerConfigData::new).collect(Collectors.toList());
this.checkLoggerConfigs(configs, NBCLIOptions.CLASSIC_HISTOGRAMS);
return configs;
}
public Maturity allowMinMaturity() {
return this.minMaturity;
}
public List<Cmd> getCommands() {
return this.cmdList;
}
public boolean wantsShowScript() {
return this.showScript;
}
public boolean wantsCompileScript() {
return this.compileScript;
}
public boolean wantsVersionCoords() {
return this.wantsVersionCoords;
}
public boolean isWantsVersionShort() {
return this.wantsVersionShort;
}
public boolean wantsActivityTypes() {
return this.wantsActivityTypes;
}
public boolean wantsTopicalHelp() {
return this.wantsActivityHelp;
}
public boolean wantsStackTraces() {
return this.showStackTraces;
}
public String wantsTopicalHelpFor() {
return this.wantsActivityHelpFor;
}
public boolean wantsBasicHelp() {
return this.wantsBasicHelp;
}
public boolean wantsEnableChart() {
return this.enableChart;
}
public boolean wantsDockerMetrics() {
return this.dockerMetrics;
}
public String wantsDockerMetricsAt() {
return this.dockerMetricsHost;
}
public int getReportInterval() {
return this.reportInterval;
}
public String wantsReportGraphiteTo() {
return this.reportGraphiteTo;
}
public String wantsReportPromPushTo() {
return this.reportPromPushTo;
}
public String wantsMetricsPrefix() {
return this.metricsPrefix;
}
public String wantsMetricsForActivity() {
return this.wantsMetricsForActivity;
}
public String getSessionName() {
return this.sessionName;
}
public NBLogLevel getConsoleLogLevel() {
return this.consoleLevel;
}
private String readWordOrThrow(final LinkedList<String> arglist, final String required) {
if (null == arglist.peekFirst())
throw new InvalidParameterException(required + " is required after this option");
return arglist.removeFirst();
}
private String[] readAllWords(final LinkedList<String> arglist) {
final String[] args = arglist.toArray(new String[0]);
arglist.clear();
return args;
}
public int getHdrDigits() {
return this.hdr_digits;
}
public String getProgressSpec() {
final ProgressSpec spec = this.parseProgressSpec(progressSpec);// sanity check
if (IndicatorMode.console == spec.indicatorMode)
if (consoleLevel.isGreaterOrEqualTo(NBLogLevel.INFO)) spec.indicatorMode = IndicatorMode.logonly;
else if (cmdList.stream().anyMatch(cmd -> CmdType.script == cmd.getCmdType()))
spec.indicatorMode = IndicatorMode.logonly;
return spec.toString();
}
private void checkLoggerConfigs(final List<LoggerConfigData> configs, final String configName) {
final Set<String> files = new HashSet<>();
configs.stream().map(LoggerConfigData::getFilename).forEach(s -> {
if (files.contains(s))
System.err.println(s + " is included in " + configName + " more than once. It will only be " +
"included " +
"in the first matching config. Reorder your options if you need to control this.");
files.add(s);
});
}
public String wantsReportCsvTo() {
return this.reportCsvTo;
}
public Path getLogsDirectory() {
return Path.of(this.logsDirectory);
}
public int getLogsMax() {
return this.logsMax;
}
public NBLogLevel getScenarioLogLevel() {
return this.logsLevel;
}
public boolean wantsInputTypes() {
return wantsInputTypes;
}
public String getScriptFile() {
if (null == scriptFile) return this.logsDirectory + File.separator + "_SESSION_" + ".js";
String expanded = this.scriptFile;
if (!expanded.startsWith(File.separator)) expanded = this.getLogsDirectory() + File.separator + expanded;
return expanded;
}
public boolean wantsMarkerTypes() {
return this.wantsMarkerTypes;
}
public boolean wantsToDumpCyclelog() {
return 0 < rleDumpOptions.length;
}
public boolean wantsToImportCycleLog() {
return 0 < cyclelogImportOptions.length;
}
public String[] getCyclelogImportOptions() {
return this.cyclelogImportOptions;
}
public String[] getCycleLogExporterOptions() {
return this.rleDumpOptions;
}
public String getConsoleLoggingPattern() {
return this.consoleLoggingPattern;
}
public Map<String, String> getLogLevelOverrides() {
return this.logLevelsOverrides;
}
public void setHistoLoggerConfigs(final String pattern, final String file, final String interval) {
//--log-histograms 'hdrdata.log:.*:2m'
this.histoLoggerConfigs.add(String.format("%s:%s:%s", file, pattern, interval));
}
public boolean wantsScenariosList() {
return this.wantsListScenarios;
}
public boolean wantsListScripts() {
return this.wantsListScripts;
}
public boolean wantsToCopyResource() {
return null != wantsToCopyWorkload;
}
public String wantsToCopyResourceNamed() {
return this.wantsToCopyWorkload;
}
public boolean wantsWorkloadsList() {
return this.wantsWorkloadsList;
}
public String getDockerGrafanaTag() {
return this.docker_grafana_tag;
}
public String getDockerPromTag() {
return this.docker_prom_tag;
}
public static class LoggerConfigData {
public String file;
public String pattern = ".*";
public String interval = "30 seconds";
public LoggerConfigData(final String histoLoggerSpec) {
final String[] words = histoLoggerSpec.split(":");
switch (words.length) {
case 3:
this.interval = words[2].isEmpty() ? this.interval : words[2];
case 2:
this.pattern = words[1].isEmpty() ? this.pattern : words[1];
case 1:
this.file = words[0];
if (this.file.isEmpty())
throw new RuntimeException("You must not specify an empty file here for logging data.");
break;
default:
throw new RuntimeException(
NBCLIOptions.LOG_HISTOGRAMS +
" options must be in either 'regex:filename:interval' or 'regex:filename' or 'filename' format"
);
}
}
public String getFilename() {
return this.file;
}
}
private static class ProgressSpec {
public String intervalSpec;
public IndicatorMode indicatorMode;
public String toString() {
return this.indicatorMode.toString() + ':' + this.intervalSpec;
}
}
private ProgressSpec parseProgressSpec(final String interval) {
final ProgressSpec progressSpec = new ProgressSpec();
final String[] parts = interval.split(":");
switch (parts.length) {
case 2:
Unit.msFor(parts[1]).orElseThrow(
() -> new RuntimeException("Unable to parse progress indicator indicatorSpec '" + parts[1] + '\'')
);
progressSpec.intervalSpec = parts[1];
case 1:
progressSpec.indicatorMode = IndicatorMode.valueOf(parts[0]);
break;
default:
throw new RuntimeException("This should never happen.");
}
return progressSpec;
}
}