private int run(String[] rawArgs) {
        boolean verbose = false;
        try {
            CliArguments cliArgs = CliArguments.fromRawArgs(rawArgs);
            var logConfigFile = cliArgs.logConfigFile().orElse(null);
            verbose = cliArgs.verboseSpecified();
            if (logConfigFile != null) {
                try (InputStream in = new BufferedInputStream(Files.newInputStream(logConfigFile))) {
                    LogManager.getLogManager().readConfiguration(in);
                    log.fine(() -> "Log configuration overridden by " + logConfigFile);
                } catch (IOException e) {
                    return handleException(verbose, "Failed to read log configuration from " + logConfigFile, e);
                }
            }
            if (cliArgs.helpSpecified()) {
                cliArgs.printHelp(systemOut);
                return 0;
            }
            if (cliArgs.versionSpecified()) {
                systemOut.println(Vespa.VERSION);
                return 0;
            }
            try (InputStream in = createFeedInputStream(cliArgs);
                 FeedClient feedClient = createFeedClient(cliArgs);
                 JsonFeeder feeder = createJsonFeeder(feedClient, cliArgs)) {
                CountDownLatch latch = new CountDownLatch(1);
                AtomicReference<FeedException> fatal = new AtomicReference<>();
                AtomicLong successes = new AtomicLong();
                AtomicLong failures = new AtomicLong();
                long startNanos = System.nanoTime();
                if (cliArgs.showProgress()) {
                    Thread progressPrinter = new Thread(() -> {
                        try {
                            while (!latch.await(10, TimeUnit.SECONDS)) {
                                synchronized (printMonitor) {
                                    printBenchmarkResult(System.nanoTime() - startNanos, successes.get(), failures.get(), feedClient.stats(), systemError);
                                }
                            }
                        }
                        catch (InterruptedException | IOException ignored) { } // doesn't happen
                    }, "progress-printer");
                    progressPrinter.setDaemon(true);
                    progressPrinter.start();
                }

                feeder.feedMany(in, new ResultCallback() {
                    @Override
                    public void onNextResult(Result result, FeedException error) { handleResult(result, error, successes, failures, cliArgs); }

                    @Override
                    public void onError(FeedException error) {
                        fatal.set(error);
                        latch.countDown();
                    }

                    @Override
                    public void onComplete() { latch.countDown(); }
                });
                latch.await();

                printBenchmarkResult(System.nanoTime() - startNanos, successes.get(), failures.get(), feedClient.stats(), cliArgs.benchmarkModeEnabled() ? systemOut : systemError);
                if (fatal.get() != null) throw fatal.get();
            }
            return 0;
        }
        catch (CliArguments.CliArgumentsException | IOException | FeedException e) {
            return handleException(verbose, e);
        }
        catch (Exception e) {
            return handleException(verbose, "Unknown failure: " + e.getMessage(), e);
        }
    }
Main method for CLI interface

@author bjorncs
vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/impl/CliClient.java