import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import cn.reghao.bnt.common.docker.DockerImpl;
import cn.reghao.bnt.common.machine.model.NetworkCard;
import cn.reghao.jutil.jdk.converter.ByteConverter;
import cn.reghao.jutil.jdk.converter.DateTimeConverter;
import cn.reghao.jutil.jdk.converter.IpAddressConverter;
import cn.reghao.jutil.jdk.thread.ThreadPoolWrapper;
import com.github.dockerjava.api.command.InspectContainerResponse;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.LoggerFactory;
import oshi.SystemInfo;
import oshi.hardware.*;
import oshi.software.os.*;
import oshi.util.FormatUtil;
import oshi.util.Util;

import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2022-05-21 13:58:00
 */
public class AgentTest {
    private static void printComputerSystem(final ComputerSystem computerSystem) {
        System.out.println("manufacturer: " + computerSystem.getManufacturer());
        System.out.println("model: " + computerSystem.getModel());
        System.out.println("serialnumber: " + computerSystem.getSerialNumber());
        final Firmware firmware = computerSystem.getFirmware();
        System.out.println("firmware:");
        System.out.println("  manufacturer: " + firmware.getManufacturer());
        System.out.println("  name: " + firmware.getName());
        System.out.println("  description: " + firmware.getDescription());
        System.out.println("  version: " + firmware.getVersion());
//      System.out.println("  release date: " + (firmware.getReleaseDate() == null ? "unknown": firmware.getReleaseDate() == null ? "unknown" : FormatUtil.formatDate(firmware.getReleaseDate())));
        final Baseboard baseboard = computerSystem.getBaseboard();
        System.out.println("baseboard:");
        System.out.println("  manufacturer: " + baseboard.getManufacturer());
        System.out.println("  model: " + baseboard.getModel());
        System.out.println("  version: " + baseboard.getVersion());
        System.out.println("  serialnumber: " + baseboard.getSerialNumber());
    }

    private static void printProcessor(CentralProcessor processor) {
        System.out.println(processor);
        System.out.println(" " + processor.getPhysicalPackageCount() + " physical CPU package(s)");
        System.out.println(" " + processor.getPhysicalProcessorCount() + " physical CPU core(s)");
        System.out.println(" " + processor.getLogicalProcessorCount() + " logical CPU(s)");

        System.out.println("Identifier: " + processor.getProcessorIdentifier());
        System.out.println("ProcessorID: " + processor.getProcessorIdentifier().getProcessorID());
    }

    private static void printCpu(CentralProcessor processor) {
        String cs = String.format("Context Switches/Interrupts: %s/%s\n",
                processor.getContextSwitches(), processor.getInterrupts());
        System.out.println(cs);
        long sleep = 1000;

        long[] prevTicks = processor.getSystemCpuLoadTicks();
        System.out.println("CPU, IOWait, and IRQ ticks @ 0 sec:" + Arrays.toString(prevTicks));
        Util.sleep(sleep);
        long[] ticks = processor.getSystemCpuLoadTicks();
        System.out.println("CPU, IOWait, and IRQ ticks @ 1 sec:" + Arrays.toString(ticks));

        long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
        long sys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
        long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
        long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
        long totalCpu = user + nice + sys + idle + iowait + irq + softirq + steal;

        String load = String.format("%.1f us, %.1f sy, %.1f ni, %.1f id, %.1f wa, %.1f hi, %.1f si, %.1f st\n",
                100d * user / totalCpu, 100d * sys / totalCpu, 100d * nice / totalCpu, 100d * idle / totalCpu,
                100d * iowait / totalCpu, 100d * irq / totalCpu, 100d * softirq / totalCpu, 100d * steal / totalCpu);
        System.out.println(load);
        /*System.out.format(
                "User: %.1f%% Nice: %.1f%% System: %.1f%% Idle: %.1f%% IOwait: %.1f%% IRQ: %.1f%% SoftIRQ: %.1f%% Steal: %.1f%%%n",
                100d * user / totalCpu, 100d * nice / totalCpu, 100d * sys / totalCpu, 100d * idle / totalCpu,
                100d * iowait / totalCpu, 100d * irq / totalCpu, 100d * softirq / totalCpu, 100d * steal / totalCpu);*/
        System.out.format("CPU load: %.1f%% (counting ticks)%n", processor.getSystemCpuLoadBetweenTicks(prevTicks) * 100);
        System.out.format("CPU load: %.1f%% (OS MXBean)%n", processor.getSystemCpuLoad(1) * 100);

        double[] loadAverage = processor.getSystemLoadAverage(3);
        /*System.out.println("CPU load averages:" +
                (loadAverage[0] < 0 ? " N/A" : String.format(" %.2f", loadAverage[0])) +
                (loadAverage[1] < 0 ? " N/A" : String.format(" %.2f", loadAverage[1])) +
                (loadAverage[2] < 0 ? " N/A" : String.format(" %.2f", loadAverage[2]))
        );*/
        String loadAvg = String.format("%s %s %s\n",
                (loadAverage[0] < 0 ? " N/A" : String.format(" %.2f", loadAverage[0])),
                (loadAverage[1] < 0 ? " N/A" : String.format(" %.2f", loadAverage[1])),
                (loadAverage[2] < 0 ? " N/A" : String.format(" %.2f", loadAverage[2]))
        );
        System.out.println(loadAvg);

        // per core CPU
//      StringBuilder procCpu = new StringBuilder("CPU load per processor:");
//      double[] load = processor.getProcessorCpuLoadBetweenTicks();
//      for (double avg : load) {
//          procCpu.append(String.format(" %.1f%%", avg * 100));
//      }
//      System.out.println(procCpu.toString());
    }

    private static void printMemory(GlobalMemory memory) {
        long total = memory.getTotal();
        long avail = memory.getAvailable();
        VirtualMemory virtualMemory = memory.getVirtualMemory();

        System.out.println("Memory: " + FormatUtil.formatBytes(memory.getAvailable()) + "/"
                + FormatUtil.formatBytes(memory.getTotal()));
        System.out.println("Swap used: " + FormatUtil.formatBytes(memory.getVirtualMemory().getSwapUsed()) + "/"
                + FormatUtil.formatBytes(memory.getVirtualMemory().getSwapTotal()));
    }

    private static void printProcesses(OperatingSystem os, GlobalMemory memory) {
        System.out.println("Processes: " + os.getProcessCount() + ", Threads: " + os.getThreadCount());
        // Sort by highest CPU
        Predicate<OSProcess> chromeProcessFilter = p -> p.getName().equalsIgnoreCase("Chrome");
        List<OSProcess> procs = os.getProcesses(chromeProcessFilter, OperatingSystem.ProcessSorting.CPU_DESC, 0);

        System.out.println("   PID  %CPU %MEM       VSZ       RSS Name");
        for (int i = 0; i < procs.size() && i < 5; i++) {
            OSProcess p = procs.get(i);
            System.out.format(" %5d %5.1f %4.1f %9s %9s %s%n", p.getProcessID(),
                    100d * (p.getKernelTime() + p.getUserTime()) / p.getUpTime(),
                    100d * p.getResidentSetSize() / memory.getTotal(), FormatUtil.formatBytes(p.getVirtualSize()),
                    FormatUtil.formatBytes(p.getResidentSetSize()), p.getName());
        }
    }

    private static void printSensors(Sensors sensors) {
        System.out.println("Sensors:");
        System.out.format(" CPU Temperature: %.1f°C%n", sensors.getCpuTemperature());
        System.out.println(" Fan Speeds: " + Arrays.toString(sensors.getFanSpeeds()));
        System.out.format(" CPU Voltage: %.1fV%n", sensors.getCpuVoltage());
    }

    private static void printPowerSources(List<PowerSource> list) {
        StringBuilder sb = new StringBuilder("Power: ");
        if (list.size() == 0) {
            sb.append("Unknown");
        } else {
            double timeRemaining = list.get(0).getTimeRemainingInstant();
            if (timeRemaining < -1d) {
                sb.append("Charging");
            } else if (timeRemaining < 0d) {
                sb.append("Calculating time remaining");
            } else {
                sb.append(String.format("%d:%02d remaining", (int) (timeRemaining / 3600),
                        (int) (timeRemaining / 60) % 60));
            }
        }
        for (PowerSource pSource : list) {
            sb.append(String.format("%n %s @ %.1f%%", pSource.getName(), pSource.getRemainingCapacityPercent() * 100d));
        }
        System.out.println(sb.toString());
    }

    private static void printDisks(List<HWDiskStore> list) {
        System.out.println("Disks:");
        for (HWDiskStore disk : list) {
            boolean readwrite = disk.getReads() > 0 || disk.getWrites() > 0;
            System.out.format(" %s: (model: %s - S/N: %s) size: %s, reads: %s (%s), writes: %s (%s), xfer: %s ms%n",
                    disk.getName(), disk.getModel(), disk.getSerial(),
                    disk.getSize() > 0 ? FormatUtil.formatBytesDecimal(disk.getSize()) : "?",
                    readwrite ? disk.getReads() : "?", readwrite ? FormatUtil.formatBytes(disk.getReadBytes()) : "?",
                    readwrite ? disk.getWrites() : "?", readwrite ? FormatUtil.formatBytes(disk.getWriteBytes()) : "?",
                    readwrite ? disk.getTransferTime() : "?");
            List<HWPartition> partitions = disk.getPartitions();
            if (partitions == null) {
                // TODO Remove when all OS's implemented
                continue;
            }
            for (HWPartition part : partitions) {
                System.out.format(" |-- %s: %s (%s) Maj:Min=%d:%d, size: %s%s%n", part.getIdentification(),
                        part.getName(), part.getType(), part.getMajor(), part.getMinor(),
                        FormatUtil.formatBytesDecimal(part.getSize()),
                        part.getMountPoint().isEmpty() ? "" : " @ " + part.getMountPoint());
            }
        }
    }

    private static void printFileSystem(FileSystem fileSystem) {
        System.out.println("File System:");

        System.out.format(" File Descriptors: %d/%d%n", fileSystem.getOpenFileDescriptors(),
                fileSystem.getMaxFileDescriptors());

        List<OSFileStore> fsArray = fileSystem.getFileStores();
        for (OSFileStore fs : fsArray) {
            long usable = fs.getUsableSpace();
            long total = fs.getTotalSpace();
            System.out.format(
                    " %s (%s) [%s] %s of %s free (%.1f%%) is %s "
                            + (fs.getLogicalVolume() != null && fs.getLogicalVolume().length() > 0 ? "[%s]" : "%s")
                            + " and is mounted at %s%n",
                    fs.getName(), fs.getDescription().isEmpty() ? "file system" : fs.getDescription(), fs.getType(),
                    FormatUtil.formatBytes(usable), FormatUtil.formatBytes(fs.getTotalSpace()), 100d * usable / total,
                    fs.getVolume(), fs.getLogicalVolume(), fs.getMount());
        }
    }

    private static void printNetworkInterfaces(List<NetworkIF> list) {
        System.out.println("Network interfaces:");
        for (NetworkIF net : list) {
            String iface = net.getName();
            String mac = net.getMacaddr();
            String ipv4 = Arrays.toString(net.getIPv4addr());
            String ipv6 = Arrays.toString(net.getIPv6addr());
            long mtu = net.getMTU();
            long speed = net.getSpeed();
            String speedStr = byteConverter.convert(speed);
            NetworkCard networkCard = new NetworkCard(iface, mac, ipv4, ipv6, mtu, speed, speedStr);

            System.out.format(" Name: %s (%s)%n", net.getName(), net.getDisplayName());
            System.out.format("   MAC Address: %s %n", net.getMacaddr());
            System.out.format("   MTU: %s, Speed: %s %n", net.getMTU(), FormatUtil.formatValue(net.getSpeed(), "bps"));
            System.out.format("   IPv4: %s %n", Arrays.toString(net.getIPv4addr()));
            System.out.format("   IPv6: %s %n", Arrays.toString(net.getIPv6addr()));
            boolean hasData = net.getBytesRecv() > 0 || net.getBytesSent() > 0 || net.getPacketsRecv() > 0
                    || net.getPacketsSent() > 0;
            System.out.format("   Traffic: received %s/%s%s; transmitted %s/%s%s %n",
                    hasData ? net.getPacketsRecv() + " packets" : "?",
                    hasData ? FormatUtil.formatBytes(net.getBytesRecv()) : "?",
                    hasData ? " (" + net.getInErrors() + " err)" : "",
                    hasData ? net.getPacketsSent() + " packets" : "?",
                    hasData ? FormatUtil.formatBytes(net.getBytesSent()) : "?",
                    hasData ? " (" + net.getOutErrors() + " err)" : "");
        }
    }

    private static void printNetworkParameters(NetworkParams networkParams) {
        System.out.println("Network parameters:");
        System.out.format(" Host name: %s%n", networkParams.getHostName());
        System.out.format(" Domain name: %s%n", networkParams.getDomainName());
        System.out.format(" DNS servers: %s%n", Arrays.toString(networkParams.getDnsServers()));
        System.out.format(" IPv4 Gateway: %s%n", networkParams.getIpv4DefaultGateway());
        System.out.format(" IPv6 Gateway: %s%n", networkParams.getIpv6DefaultGateway());
    }

    private static void printDisplays(List<Display> list) {
        System.out.println("Displays:");
        int i = 0;
        for (Display display : list) {
            System.out.println(" Display " + i + ":");
            System.out.println(display.toString());
            i++;
        }
    }

    private static void printUsbDevices(List<UsbDevice> list) {
        System.out.println("USB Devices:");
        for (UsbDevice usbDevice : list) {
            System.out.println(usbDevice.toString());
        }
    }

    static void setLogLevel() {
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        Logger rootLogger = loggerContext.getLogger("ROOT");
        rootLogger.setLevel(Level.INFO);
    }

    static List<ListenProcess> getListenProcesses() {
        IpAddressConverter ipAddressConverter = new IpAddressConverter();
        List<SysProcess> sysProcessList = new ArrayList<>();
        os.getProcesses().forEach(osProcess -> {
            int pid = osProcess.getProcessID();
            String name = osProcess.getName();
            int ppid = osProcess.getParentProcessID();
            String state = osProcess.getState().name();
            List<OSThread> osThreadList = osProcess.getThreadDetails();
            sysProcessList.add(new SysProcess(pid, name, ppid));
        });

        String state = InternetProtocolStats.TcpState.LISTEN.name();
        List<ListenProcess> list = new ArrayList<>();
        os.getInternetProtocolStats().getConnections().forEach(ipConnection -> {
            if (!ipConnection.getState().name().equals(state)) {
                return;
            }

            String type = ipConnection.getType();
            int pid = ipConnection.getowningProcessId();
            byte[] localAddress = ipConnection.getLocalAddress();
            int localPort = ipConnection.getLocalPort();
            byte[] remoteAddress = ipConnection.getForeignAddress();
            int remotePort = ipConnection.getForeignPort();
            System.out.printf("%s %s %s %s\n", pid, type, state, localPort);
            list.add(new ListenProcess(pid, type, localPort));
        });

        Map<Integer, List<ListenProcess>> groupMap = list.stream().collect(Collectors.groupingBy(ListenProcess::getPid));
        os.getProcesses().forEach(osProcess -> {
            int pid = osProcess.getProcessID();
            List<ListenProcess> list1 = groupMap.get(pid);
            if (list1 != null && !list1.isEmpty()) {
                String name = osProcess.getName();
                list1.get(0).setName(name);
            }
        });

        return list;
    }

    static OSProcess getProcess(int pid) {
        List<OSProcess> list = os.getProcesses().stream()
                .filter(osProcess -> osProcess.getProcessID() == pid)
                .collect(Collectors.toList());
        return list.isEmpty() ? null : list.get(0);
    }

    static List<InternetProtocolStats.IPConnection> getProcessConnections(int pid, InternetProtocolStats.TcpState tcpState) {
        return os.getInternetProtocolStats().getConnections().stream()
                .filter(ipConnection -> ipConnection.getowningProcessId() == pid
                        && ipConnection.getState().name().equals(tcpState.name()))
                .collect(Collectors.toList());
    }

    static List<InternetProtocolStats.IPConnection> getProcessConnections(int pid, boolean containListen) {
        String state = InternetProtocolStats.TcpState.LISTEN.name();
        return os.getInternetProtocolStats().getConnections().stream()
                .filter(ipConnection -> ipConnection.getowningProcessId() == pid
                        && (containListen == ipConnection.getState().name().equals(state)))
                .collect(Collectors.toList());
    }

    static void dockerListTest() {
        List<ListenProcess> listenProcessList = getListenProcesses();
        Map<Integer, List<ListenProcess>> groupMap = listenProcessList.stream().collect(Collectors.groupingBy(ListenProcess::getPid));

        DockerImpl docker = new DockerImpl();
        List<InspectContainerResponse> list = docker.psAll();
        List<DockerProcess> dockerProcessList = new ArrayList<>();
        for (InspectContainerResponse response : list) {
            String imageId = response.getImageId();
            Boolean running = response.getState().getRunning();
            if (running != null && running) {
                Integer pid = response.getState().getPid();
                if (pid == null) {
                    pid = -1;
                }

                String containerId = response.getId();
                String appId = response.getName().replace("/", "");
                System.out.printf("%s: %s -> %s\n", pid, containerId, appId);
                dockerProcessList.add(new DockerProcess(pid, containerId, appId));
            }
        }

        System.out.println();
    }

    @Setter
    @Getter
    static class ListenProcess {
        private int pid;
        private String name;
        private String type;
        private int port;

        public ListenProcess(int pid, String type, int port) {
            this.pid = pid;
            this.type = type;
            this.port = port;
        }
    }

    @AllArgsConstructor
    @Getter
    static class DockerProcess {
        private int pid;
        private String containerId;
        private String appId;
    }

    @AllArgsConstructor
    @Getter
    static class SysProcess {
        private int pid;
        private String name;
        private int ppid;
    }

    static SystemInfo si = new SystemInfo();
    static HardwareAbstractionLayer hal = si.getHardware();
    static OperatingSystem os = si.getOperatingSystem();
    static ByteConverter byteConverter = new ByteConverter();
    static ScheduledExecutorService scheduler = ThreadPoolWrapper.scheduledThreadPool("heartbeat", 5);

    static void getProcessInfo(int pid) throws InterruptedException {
        OSProcess osProcess = getProcess(pid);
        if (osProcess == null) {
            return;
        }

        long startTime = osProcess.getStartTime();
        String groupId = osProcess.getGroupID();
        String group = osProcess.getGroup();
        String userId = osProcess.getUserID();
        String user = osProcess.getUser();
        String commandLine = osProcess.getCommandLine();
        String path = osProcess.getPath();

        StatTask statTask = new StatTask(pid);
        scheduler.scheduleAtFixedRate(statTask, 0, 3, TimeUnit.SECONDS);
        System.out.println("main-thread goto sleep");
        Thread.sleep(3600_000);
    }

    public static void main(String[] args) throws Exception {
        //setLogLevel();
        int pid = 1483161;
        getProcessInfo(pid);
        //List<InternetProtocolStats.IPConnection> processConnections = getProcessConnections(pid, tcpState);

        /*getListenProcesses();
        CentralProcessor centralProcessor = hal.getProcessor();
        printProcessor(centralProcessor);
        System.out.println("--------------------------------------------------");
        printCpu(centralProcessor);*/

        /*long bootTime = os.getSystemBootTime();
        String bootAt = DateTimeConverter.format(bootTime*1000);
        long uptime = os.getSystemUptime();
        List<OSSession> osSessionList = os.getSessions();
        int sessionCount = osSessionList.size();
        String loadAvg = "";
        int processCount = os.getProcessCount();*/
        /*Map<String, List<OSProcess>> groupMap = os.getProcesses().stream()
                .collect(Collectors.groupingBy(osProcess -> osProcess.getState().name()));
        System.out.println();*/

        /*System.out.println("--------------------------------------------------");
        System.out.println("Checking Memory...");
        printMemory(hal.getMemory());*/

        /*System.out.println("--------------------------------------------------");
        System.out.println("Checking Network interfaces...");
        printNetworkInterfaces(hal.getNetworkIFs());*/

        //System.out.println("Checking Network parameterss...");
        //printNetworkParameters(os.getNetworkParams());

        /*
        os.getProcesses().forEach(osProcess -> {
            int pid = osProcess.getProcessID();
            String name = osProcess.getName();
            System.out.printf("%s -> %s\n", pid, name);
        });

        IpAddressConverter ipAddressConverter = new IpAddressConverter();
        os.getInternetProtocolStats().getConnections().forEach(ipConnection -> {
            String type = ipConnection.getType();
            String state = ipConnection.getState().name();
            int pid = ipConnection.getowningProcessId();
            byte[] localAddress = ipConnection.getLocalAddress();
            int localPort = ipConnection.getLocalPort();
            byte[] remoteAddress = ipConnection.getForeignAddress();
            int remotePort = ipConnection.getForeignPort();

            if (localPort != 3306) {
                return;
            }
            System.out.printf("%s %s %s %s\n", pid, type, state, localPort);
        });*/

        /*Predicate<OSProcess> chromeProcessFilter = p -> p.getName().equalsIgnoreCase("Chrome");
        List<OSProcess> procs = os.getProcesses(chromeProcessFilter, OperatingSystem.ProcessSorting.CPU_DESC, 10);
        procs.forEach(System.out::println);*/
/*
        System.out.println("Checking computer system...");
        printComputerSystem(hal.getComputerSystem());

        System.out.println("Checking Processes...");
        printProcesses(os, hal.getMemory());*/

        /*while (!Thread.interrupted()) {
            //printSensors(hal.getSensors());
            printProcesses(os, hal.getMemory());
            try {
                Thread.sleep(1_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }*/

        /*System.out.println("Checking Sensors...");
        printSensors(hal.getSensors());*/

        /*System.out.println("Checking Power sources...");
        printPowerSources(hal.getPowerSources());*/

        /*
        System.out.println("Checking Displays...");
        printDisplays(hal.getDisplays());

        System.out.println("Checking USB Devices...");
        printUsbDevices(hal.getUsbDevices(true));*/
    }

    static class StatTask implements Runnable {
        private final int pid;

        public StatTask(int pid) {
            this.pid = pid;
        }

        public void run() {
            OSProcess osProcess = getProcess(pid);
            if (osProcess == null) {
                return;
            }

            List<OSThread> osThreadList = osProcess.getThreadDetails();
            List<InternetProtocolStats.IPConnection> processConnections = getProcessConnections(pid, false);
            long contextSwitches = osProcess.getContextSwitches();
            double cpuLoadCumulative = osProcess.getProcessCpuLoadCumulative();

            long uptime = osProcess.getUpTime();
            long kernelTime = osProcess.getKernelTime();
            long userTime = osProcess.getUserTime();

            String state = osProcess.getState().name();
            int priority = osProcess.getPriority();
            long affinityMask = osProcess.getAffinityMask();

            long residentSetSize= osProcess.getResidentSetSize();
            long virtualSize = osProcess.getVirtualSize();

            long openFiles = osProcess.getOpenFiles();
            long bytesRead = osProcess.getBytesRead();
            long bytesWritten = osProcess.getBytesWritten();

            System.out.printf("%s -> threads: %s, connections: %s, " +
                            "contextSwitches: %s, cpuLoadCumulative: %s, " +
                            "uptime: %s, kernelTime: %s, userTime: %s, " +
                            "state: %s, priority: %s, affinityMask: %s, " +
                            "residentSetSize: %s, virtualSize: %s, " +
                            "openFiles: %s, bytesRead: %s, bytesWritten: %s, " +
                            "\n",
                    DateTimeConverter.format(System.currentTimeMillis()), osThreadList.size(), processConnections.size(),
                    contextSwitches, cpuLoadCumulative,
                    uptime, kernelTime, userTime,
                    state, priority, affinityMask,
                    residentSetSize, virtualSize,
                    openFiles, bytesRead, bytesWritten);
        }
    }
}
