001package co.codewizards.cloudstore.core.util;
002
003import java.util.Map;
004import java.util.TreeMap;
005
006import org.slf4j.Logger;
007import org.slf4j.LoggerFactory;
008
009public final class DebugUtil {
010
011        private static final Logger logger = LoggerFactory.getLogger(DebugUtil.class);
012
013        private static final long KIB = 1024L;
014        private static final long MIB = KIB * 1024;
015        private static final long GIB = MIB * 1024;
016        private static final long TIB = GIB * 1024;
017
018        private DebugUtil() {
019        }
020
021        public static void logMemoryStats(Logger logger) {
022                if (logger == null)
023                        logger = DebugUtil.logger;
024
025                if (! logger.isInfoEnabled())
026                        return;
027
028                final Runtime runtime = Runtime.getRuntime();
029
030                runtime.gc();
031
032                // max: limit of maximum allocatable memory allowed to the VM. Likely specified by -Xmx...
033                final long max = runtime.maxMemory();
034
035                // allocated: memory currently allocated by the VM (requested from and granted by the OS). Might be less than 'max'.
036                final long allocated = runtime.totalMemory();
037
038                // used: memory in use by Java objects (hence we invoke gc() above, otherwise this doesn't say anything useful).
039                final long used = allocated - runtime.freeMemory();
040
041                // available: how much this JVM can still use for future objects -- with or without the need to allocate more from the OS.
042                final long available = max - used;
043
044                logger.info("logMemoryStats: max={}, allocated={}, used={}, available={}",
045                                getHumanReadableSize(max),
046                                getHumanReadableSize(allocated),
047                                getHumanReadableSize(used),
048                                getHumanReadableSize(available));
049        }
050
051        private static String getHumanReadableSize(final long size) {
052                if (size >= TIB)
053                        return String.format("%.1f TiB", (double) size / TIB);
054
055                if (size >= GIB)
056                        return String.format("%.1f GiB", (double) size / GIB);
057
058                if (size >= MIB)
059                        return String.format("%.1f MiB", (double) size / MIB);
060
061                if (size >= KIB)
062                        return String.format("%.1f KiB", (double) size / KIB);
063
064                return String.format("%d B", size);
065        }
066
067        public static void logSystemProperties() {
068                if (! logger.isDebugEnabled()) {
069                        return;
070                }
071                TreeMap<String, String> sortedSystemProperties = new TreeMap<>();
072                for (Map.Entry<Object, Object> me : System.getProperties().entrySet()) {
073                        String key = String.valueOf(me.getKey());
074                        String value = String.valueOf(me.getValue());
075                        sortedSystemProperties.put(key, value);
076                }
077                logger.debug(">>> System properties BEGIN >>>");
078                for (Map.Entry<String, String> me : sortedSystemProperties.entrySet()) {
079                        logger.debug("  * {} = {}", me.getKey(), me.getValue());
080                }
081                logger.debug("<<< System properties END <<<");
082        }
083}