class Progress implements AutoCloseable {
    private final Logger logger;
    private final Long totalCount;
    private final String suffix;

    private final AtomicLong currentCount = new AtomicLong();
    private final Map<Level, Integer> levelCountMap = new TreeMap<>(Comparator.comparingInt(Level::intValue).reversed());
    private Thread loggerThread = null;
    private volatile boolean run;

    private final Level baseLogLevel;

    private final Object sync = new Object();

    /**
     * @param logger logger instance
     * @param suffix string suffix to identify the operation
     * @param totalCount total count
     * @param logLevel base log level
     * @param isPrintProgress whether to print the progress
     */
    public Progress(Logger logger, String suffix, long totalCount, Level logLevel, boolean isPrintProgress) {
        this.logger = logger;
        this.suffix = suffix;
        this.baseLogLevel = logLevel;

        if (totalCount < 0) {
            this.totalCount = null;
        } else {
            this.totalCount = totalCount;
        }

        // Note: Level.CONFIG is missing as it does not make too much sense for progress reporting semantically.
        final List<Level> standardLevels = Arrays.asList(Level.OFF, Level.SEVERE, Level.WARNING, Level.INFO,
                Level.FINE, Level.FINER, Level.FINEST, Level.ALL);
        int[] num = new int[]{100, 50, 10, 1};
        for (int i = standardLevels.indexOf(baseLogLevel), j = 0;
             i < standardLevels.size() && j < num.length; i++, j++) {

            Level level = standardLevels.get(i);
            levelCountMap.put(level, num[j]);
        }

        // Assuming the printProgress configuration setting cannot be changed on the fly.
        if (!baseLogLevel.equals(Level.OFF) && isPrintProgress) {
            spawnLogThread();
        }
    }

    private void spawnLogThread() {
        // spawn a logger thread.
        run = true;
        loggerThread = new Thread(this::logLoop,
                "progress-thread-" + suffix.replace(" ", "_"));
        loggerThread.start();
    }

    /**
     * Increment counter. The actual logging will be done eventually.
     */
    public void increment() {
        this.currentCount.incrementAndGet();

        if (loggerThread != null) {
            // nag the thread.
            synchronized (sync) {
                sync.notifyAll();
            }
        }
    }

    private void logLoop() {
        long cachedCount = 0;
        Map<Level, Long> lastLoggedChunk = new HashMap<>();

        while (true) {
            long longCurrentCount = this.currentCount.get();
            Level currentLevel = Level.FINEST;

            // Do not log if there was no progress.
            if (cachedCount < longCurrentCount) {
                currentLevel = getLevel(lastLoggedChunk, longCurrentCount, currentLevel);
                logIt(lastLoggedChunk, longCurrentCount, currentLevel);
            }

            if (!run) {
                return;
            }

            cachedCount = longCurrentCount;

            // wait for event
            try {
                synchronized (sync) {
                    if (!run) {
                        // Loop once more to do the final logging.
                        continue;
                    }
                    sync.wait();
                }
            } catch (InterruptedException e) {
                logger.log(Level.WARNING, "logger thread interrupted");
            }
        }
    }

    @VisibleForTesting
    Level getLevel(Map<Level, Long> lastLoggedChunk, long currentCount, Level currentLevel) {<FILL_FUNCTION_BODY>}

    private void logIt(Map<Level, Long> lastLoggedChunk, long currentCount, Level currentLevel) {
        if (logger.isLoggable(currentLevel)) {
            lastLoggedChunk.put(currentLevel, currentCount / levelCountMap.get(currentLevel));
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("Progress: ");
            stringBuilder.append(currentCount);
            stringBuilder.append(" ");
            if (totalCount != null) {
                stringBuilder.append("(");
                stringBuilder.append(String.format("%.2f", currentCount * 100.0f / totalCount));
                stringBuilder.append("%) ");
            }
            stringBuilder.append(suffix);
            logger.log(currentLevel, stringBuilder.toString());
        }
    }

    @Override
    public void close() {
        if (loggerThread == null) {
            return;
        }

        try {
            run = false;
            synchronized (sync) {
                sync.notifyAll();
            }
            loggerThread.join();
        } catch (InterruptedException e) {
            logger.log(Level.WARNING, "logger thread interrupted");
        }
    }
}

        // The intention is to log the initial and final count at the base log level.
        if (currentCount <= 1 || (totalCount != null && currentCount == totalCount)) {
            currentLevel = baseLogLevel;
        } else {
            // Set the log level based on the "buckets".
            for (var levelCountItem : levelCountMap.entrySet()) {
                if (lastLoggedChunk.getOrDefault(levelCountItem.getKey(), -1L) <
                        currentCount / levelCountItem.getValue()) {
                    currentLevel = levelCountItem.getKey();
                    break;
                }
            }
        }
        return currentLevel;
    
<no_super_class>