Monitor Linux System Using Java-CPU&Disk&Memory&Network

2 篇文章 0 订阅
2 篇文章 0 订阅

Linux下Java獲取CPU、内存、磁盤IO、网络相應信息

這個話題不是一個很新的東西,很多工具都做了這方面的工作。出於個人興趣,我就實作一個小工具,實現了:

  • CPU【user】【sys 】【iowait】的動態讀取
  • Network【Receice】【Transmit】的動態讀取
  • Disk【rkB/s】【wkB/s】的動態讀取
  • Memeory【内存使用率】的動態分析
    模仿的對象

參考數據PDFLinux System and Performance Monitoring

開發環境:大部分代碼我是在win10MyEclipse下進行語法檢查的,細緻的編寫是在CentOS 7gedit,編譯則是在Terminal(虛擬機下的CentOS 7實在是承受不了MyEclipse(太耗CPU和内存),本身在Terminal 下打開java程序就很慢。)。

其實gedit也是一個非常優秀的Coding Tool。
这里写图片描述

CentOS 7版本:

[root@localhost ~]# uname -a
Linux localhost.localdomain 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

JDK版本:(果斷放棄自帶的OpenJDK)

[root@localhost ~]# java -version
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)

1. 原理

下面是我的思考過程:
如果單單是利用Linux下的指令,很容易獲取相應的信息,如:使用iostat -c查看CPU的使用率情况。

備注:如果這個指令找不到,需要先安裝sysstat。我在rhl5上測試這條指令時就提示無法找到這條指令。當然超簡單的。

[root@localhost class]# iostat -c
Linux 3.10.0-229.el7.x86_64 (localhost.localdomain)     20161225日     _x86_64_    (2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          14.17    0.21    2.09    0.38    0.00   83.15

现在想用java来获取?怎么写呢?之前我想,在linux環境下,用管道把指令獲取的信息保存在TXT文件裏,用java去讀取文件的内容,不就可以實現抓取linux系統的相應信息。

[root@localhost ~]# iostat -c -> cpu.txt
[root@localhost ~]# cat cpu.txt
Linux 3.10.0-229.el7.x86_64 (localhost.localdomain)     20161225日     _x86_64_(2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          11.56    0.16    1.73    0.31    0.00   86.24

但是這樣太複雜了,頻繁的創建文件讀文件也顯得繁瑣,有沒有一種直接的方法呢?上網咯查了知道:

java中調用Linux的shell命令使用使用Process和Runtime
jdk1.6 API doc:
public class Runtime extends Object
每个 Java 应用程序都有一个 Runtime 类實例,使应用程序能够与其运行的環境相连接。可以通過getRuntime 方法獲取当前运行时。 應用程序不能创建自己的 Runtime类实例。
public abstract class Process extends Object
ProcessBuilder.start() 和Runtime.exec 方法创建一个本机进程,并返回 Process子类的一个實例,该實例可用来控制進程并获得相关信息。

像這樣:

String command = "iostat -c";
Runtime r = Runtime.getRuntime();
Process pro = r.exec(command);
BufferedReader in = new BufferedReader(new InputStreamReader(pro.getInputStream()));

儅我們拿到一個BufferedReader,就可以一行一行的提取我們想要的信息。那麽問題來了,怎麽畫成圖標呢?難不成還要java自帶的類庫【大腦迅速搜索相關的類庫】畫?

這裏我們可以用JFree Chart

什麽是JFree Chart?以下是引自百度。

JFreeChart是JAVA平台上的一个开放的图表绘制类库。它完全使用JAVA语言编写,是为applications, applets,servlets 以及JSP等使用所设计。JFreeChart可生成饼图(pie charts)、柱状图(bar charts)、散点图(scatter plots)、时序图(time series)、甘特图(Gantt charts)等等多种图表,并且可以产生PNG和JPEG格式的输出,还可以与PDF和EXCEL关联。

JFreeChart舉例:

    TimeSeries timeseries1 = new TimeSeries("user%");
    TimeSeries timeseries2 = new TimeSeries("sys%");
    TimeSeries timeseries3 = new TimeSeries("iowait%");
    TimeSeriesCollection timeseriescollection = new TimeSeriesCollection();
    timeseriescollection.addSeries(timeseries1); 
    timeseriescollection.addSeries(timeseries2);
    timeseriescollection.addSeries(timeseries3);

    JFreeChart jfreechart = ChartFactory.createTimeSeriesChart("CPU Total Usage","Time(s)","Value(%)", timeseriescollection,true,true,false);
     jfreechart.setBackgroundPaint(Color.white);         

     XYPlot xyplot = jfreechart.getXYPlot();       
     ValueAxis valueaxis = xyplot.getDomainAxis();
     valueaxis.setAutoRange(true);
     valueaxis.setFixedAutoRange(60000D);
     ChartPanel CPUframe = new ChartPanel(jfreechart,true); 

2.準備-通用類

這是一個通過linux下的指令,拿到指令内容的BufferedReader 的類。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.FileInputStream;

/*
 * function:get the info<BufferedReader> by using Linux command
 */
public class LinuxCommand {
    private Process pro = null;
    private String command = null;

    public LinuxCommand(String command) {
        this.command = command;
    }

    public BufferedReader getInfoReader() {

        try {
            Runtime r = Runtime.getRuntime();
            pro = r.exec(command);
            return new BufferedReader(new InputStreamReader(pro.getInputStream()));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } 
    }

    public BufferedReader getInfoReader2() {
        try {
            return new BufferedReader(new InputStreamReader(new FileInputStream(command)));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } 
    }

    public void processDestroy() {
        if(pro != null)
            pro.destroy();
    }
}

3. CPU

這個類的功能是返回一個TimeSeriesChart的圖標的JPanel,同時本生是實現了Runnable接口。自身起了一個綫程,每隔一秒讀取一次“iostat -c”指令獲取【user】【sys 】【iowait】這三個信息。

 * user% :在用户级别运行所使用 CPU 的百分比。
 * sys% :在系统级别(kernel)运行所使用 CPU 的百分比。
 * iowait% :CPU等待硬件 I/O 时,所占用 CPU 百分比。

具體代碼:

import java.awt.Color;
import java.io.BufferedReader;
import java.io.IOException;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;


public class CPUTimeSeries implements Runnable{
    ChartPanel CPUframe;

    private TimeSeries timeseries1;
    private TimeSeries timeseries2;
    private TimeSeries timeseries3;
    static Thread thread;
    private double value1 ,value2, value3;
    private static String command = "iostat -c";   
    private LinuxCommand linuxcommand  = null;     
    private BufferedReader in = null;

    public CPUTimeSeries(){
         linuxcommand  = new LinuxCommand(command);
         thread = new Thread(this);
         XYDataset xydataset = createDataset();  
         JFreeChart jfreechart = ChartFactory.createTimeSeriesChart("CPU Total Usage","Time(s)","Value(%)",
                 xydataset,true,true,false);
         jfreechart.setBackgroundPaint(Color.white);         

         XYPlot xyplot = jfreechart.getXYPlot();       
         ValueAxis valueaxis = xyplot.getDomainAxis();
         valueaxis.setAutoRange(true);
         valueaxis.setFixedAutoRange(60000D);
         CPUframe = new ChartPanel(jfreechart,true); 
    }


    //produce DataSet  
    private XYDataset createDataset() {
        timeseries1 = new TimeSeries("user%");
        timeseries2 = new TimeSeries("sys%");
        timeseries3 = new TimeSeries("iowait%");
        TimeSeriesCollection timeseriescollection = new TimeSeriesCollection();
        timeseriescollection.addSeries(timeseries1); 
        timeseriescollection.addSeries(timeseries2);
        timeseriescollection.addSeries(timeseries3);
        return timeseriescollection;
    }

    //return a new Panel
    public ChartPanel getChartPanel(){  
           return CPUframe;    
    }

    public void startThread(){
        thread.start();
    }
    public void clearDataSet() {
        this.timeseries1.clear();
        this.timeseries2.clear();
        this.timeseries3.clear();
    }

    @Override
    public void run() {
         while(true){  
            try {  
                in = linuxcommand.getInfoReader();
                String line = null; 
                int cnt = 0;
                while((line=in.readLine()) != null && ++cnt != 4){ 
                } 
                line = line.trim();  
                String[] temp = line.split("\\s+");
                //string to double
                value1 = Double.parseDouble(temp[0]);
                value2 = Double.parseDouble(temp[2]);
                value3 = Double.parseDouble(temp[3]);
                //fufill the timeseries
                try {
                 Millisecond millisecond1 = new Millisecond();
                 timeseries1.add(millisecond1, value1);
                 timeseries2.add(millisecond1, value2);
                 timeseries3.add(millisecond1, value3);
                 Thread.sleep(1000);
             }catch(InterruptedException e) {
                 e.printStackTrace();
             }
                in.close();  
                linuxcommand.processDestroy();               
            } catch (IOException e) {  
                e.printStackTrace();  
            }       
         }
    }    
}
  • 結果截圖
    CPU結果截圖

4. Network

這個類的功能是返回一個XYAreaChart, 自身起一個綫程每秒讀取指令/proc/net/dev 指令下的【Receice】【Transmit】數據。

[root@localhost class]# cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
eno16777736: 303041758  228598    0    0    0     0          0         0  4846830   58293    0    0    0     0       0          0
    lo:   25702     266    0    0    0     0          0         0    25702     266    0    0    0     0       0          0

關鍵代碼(重寫的run()方法):
由於【Receice】【Transmit】是一個纍積數據,所以我們想要獲取一秒内的數據傳輸量,data = new - old ,同樣的道理,如果想要獲取網口傳輸速度,衹要把時間t弄得短一些,用data / t 就是網口傳輸速度。

long startTime = System.currentTimeMillis();
long endTime = System.currentTimeMillis();  
t = startTime  - endTime ;

有把這三個數據放在一張表中,如果這樣的話,就有兩個坐標Y軸(單位不統一),複雜了很多,之後的版本想做一下,這個版本就簡單的實現對R&T的動態讀取,應該值得注意的是R&T的單位是byte

    @Override
    public void run() {
        while(true) {
            in = linuxcommand.getInfoReader2();
            String line = null; 
            try {
                line = in.readLine();
                line = in.readLine();
                line = in.readLine();//the data we looking for
                in.close(); 
                String[] temp = line.split("[\\s]+");
                rece2 = Long.parseLong(temp[1]);
                tran2 = Long.parseLong(temp[9]);
            } catch (IOException e2) {
                e2.printStackTrace();
            }       
            value1 = (rece2 - rece1) * 8.0D / 1024;
            value2 = (tran2 - tran1) * 8.0D / 1024;
            rece1 = rece2;
            tran1 = tran2;
             Millisecond millisecond = new Millisecond();
             timeseries1.add(millisecond, value1);
             timeseries2.add(millisecond, value2);
             try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }    

Network結果截圖

5. Disk

這個類是獲取磁盤IO每秒讀寫的數據量,用到JFreeChart裏的TimeSeriesChart, 道理也和之前的兩個模塊的差不多,不同的是,有多個設備,需要根據用戶的選擇提取相應的設備信息。

[root@localhost class]# iostat -k -d -x
Linux 3.10.0-229.el7.x86_64 (localhost.localdomain)     20161226日     _x86_64_    (2 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.05     0.60    2.42    0.84   124.89    57.36   112.00     0.14   42.80   16.44  118.90   4.10   1.33
scd0              0.00     0.00    0.01    0.00     0.02     0.00     4.14     0.00    3.10    3.10    0.00   3.10   0.00
dm-0              0.00     0.00    2.38    0.96   124.08    55.63   107.60     0.19   58.09   16.74  159.94   3.94   1.32
dm-1              0.00     0.00    0.03    0.42     0.14     1.68     8.00     0.06  130.92   21.02  139.85   0.65   0.03

從上面我們可以看出有4個設備的IO讀寫信息,我還提供了一個ALL 的選項,該選項是計算所有IO設備讀寫之和。
關鍵代碼:

    @Override
    public void run() {
        while(true) {
            //prepare the collect
            in = linuxcommand.getInfoReader(); 
            String line = null;
            try {//skip three lines
                line = in.readLine();
                line = in.readLine();
                line = in.readLine();
            } catch (IOException e2) {
                e2.printStackTrace();
            }
            //collect the data
            if(this.changed == true) {
                this.timeseries1.clear();
                this.timeseries2.clear();
                value1 = value2 = 0.0D;
                //change the show state
                this.changed = false;
            }
            if(state.equals("all") == true) {
                try {
                    value1 = value2 = 0.0D;
                    while((line = in.readLine()) != null) {
                        if(line.equals("") == true)
                            break;                      
                        String[] temp = line.split("[\\s]+");
                        value1 += Double.parseDouble(temp[5]);
                        value2 += Double.parseDouble(temp[6]);
                    }
                    in.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }   
            }else {
                try {
                    while((line = in.readLine()) != null) {
                        if(line.equals("") == true)
                            break;
                        String[] temp = line.split("[\\s]+");
                        if(temp[0].equals(this.state)) {
                            value1 = Double.parseDouble(temp[5]);
                            value2 = Double.parseDouble(temp[6]);
                            break;
                        }
                    }   
                    in.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }   
            }
            this.fillTimeSeries(value1, value2);
             try {
                Thread.sleep(1000);
             } catch (InterruptedException e) {
                e.printStackTrace();
             }
            linuxcommand.processDestroy();
        }
    } 

代碼注釋少,一部分原因是在win 10寫的中文注釋在linux下會亂碼和我英文不好,一部分原因是我懶,主要是因爲懶。T_T。
Disk結果截圖

6. Memory

這個類是實現了動態分析内存的使用率,遇到的linux指令是/proc/meminfo ,需要的數據衹是前五行。

% = (MemTotal - MemFree - Buffers - Cached) / MemTotal * 100
備注:rhl5下這條指令的結果沒有MemAvailable, 并且我門也不使用它。(這就是我程序的局限性,換了臺機子,估計就跑不正確了。)

[root@localhost class]# cat /proc/meminfo
MemTotal:        1870516 kB
MemFree:          112008 kB
MemAvailable:     401968 kB
Buffers:              72 kB
Cached:           384544 kB
SwapCached:         4120 kB
Active:           894496 kB
.........................

關鍵代碼:


    @Override
    public void run() {
        while(true) {
                    in = linuxcommand.getInfoReader2();
                    String line = null; 
                    try {
                        for(int i=0 ; i<5 ; ++i) {
                            line = in.readLine();
                            mem[i] = Long.parseLong(line.split("\\s+")[1]);
                        } 
                        in.close();  
                    } catch (IOException e2) {
                        e2.printStackTrace();
                    }
                    //Fulfill the dataset           
                    for(int i=0 ; i<19 ; ++i) {
                        value[i] = value[i+1];
                        categoryDataset.addValue(value[i], "", "" + i);
                    }
                    value[19] = 100.0D * (mem[0] - mem[1] - mem[3] - mem[4]) / mem[0];
                    categoryDataset.addValue(value[19], "", "19");
                 try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                            e.printStackTrace();
                    }

                }   
        }    

Memory結果截圖

7. 編譯運行

把所有源代碼放在一個文件下,比如説src
編譯:
進入源代碼目錄下:

cd ../src
//將輸出的字節碼文件統一放到該目錄下的class文件夾下
javac -d class *.java

運行:
進入該目錄下的class文件夾下

cd class
//我的main函數在類MainFrame里
java MainFrame

GitHub源碼

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值