Browse Source

第一次提交

zuoxiupeng 4 years ago
parent
commit
082e3e1644
100 changed files with 32887 additions and 0 deletions
  1. 1 0
      License
  2. 5 0
      build.bat
  3. 25 0
      config/cfg.ini
  4. 117 0
      control
  5. 212 0
      http/http.go
  6. 61 0
      http/websocket.go
  7. 13 0
      i18n/en_US.json
  8. 0 0
      i18n/zh-CN.json
  9. 4 0
      libs/collection/collection.go
  10. 46 0
      libs/collection/cpuinfo.go
  11. 84 0
      libs/collection/disk.go
  12. 15 0
      libs/collection/host.go
  13. 19 0
      libs/collection/load.go
  14. 36 0
      libs/collection/meminfo.go
  15. 82 0
      libs/collection/network.go
  16. 166 0
      libs/collection/ping.go
  17. 47 0
      libs/collection/process.go
  18. 128 0
      libs/collection/process_unix.go
  19. 75 0
      libs/collection/process_windows.go
  20. 106 0
      libs/collection/stat.go
  21. 92 0
      libs/common/aes.go
  22. 102 0
      libs/common/common.go
  23. 19 0
      libs/common/exec.go
  24. 51 0
      libs/common/license.go
  25. 14 0
      libs/common/logs.go
  26. 5 0
      libs/common/rootdir_unix.go
  27. 5 0
      libs/common/rootdir_windows.go
  28. 116 0
      libs/config/config.go
  29. 2 0
      libs/modules/config/ping_hosts
  30. 17 0
      libs/modules/shell_files/arp_cache.sh
  31. 6 0
      libs/modules/shell_files/bandwidth.sh
  32. 11 0
      libs/modules/shell_files/common_applications.sh
  33. 7 0
      libs/modules/shell_files/cpu_info.sh
  34. 13 0
      libs/modules/shell_files/cpu_intensive_processes.sh
  35. 33 0
      libs/modules/shell_files/cpu_utilization.sh
  36. 18 0
      libs/modules/shell_files/cron_history.sh
  37. 14 0
      libs/modules/shell_files/current_ram.sh
  38. 4 0
      libs/modules/shell_files/disk_partitions.sh
  39. 40 0
      libs/modules/shell_files/download_transfer_rate.sh
  40. 28 0
      libs/modules/shell_files/general_info.sh
  41. 9 0
      libs/modules/shell_files/internet_speed.sh
  42. 7 0
      libs/modules/shell_files/io_stats.sh
  43. 15 0
      libs/modules/shell_files/ip_addresses.sh
  44. 10 0
      libs/modules/shell_files/load_avg.sh
  45. 4 0
      libs/modules/shell_files/logged_in_users.sh
  46. 7 0
      libs/modules/shell_files/memcached.sh
  47. 4 0
      libs/modules/shell_files/memory_info.sh
  48. 13 0
      libs/modules/shell_files/network_connections.sh
  49. 7 0
      libs/modules/shell_files/number_of_cpu_cores.sh
  50. 28 0
      libs/modules/shell_files/ping.sh
  51. 12 0
      libs/modules/shell_files/ram_intensive_processes.sh
  52. 10 0
      libs/modules/shell_files/recent_account_logins.sh
  53. 18 0
      libs/modules/shell_files/redis.sh
  54. 88 0
      libs/modules/shell_files/scheduled_crons.sh
  55. 5 0
      libs/modules/shell_files/swap.sh
  56. 40 0
      libs/modules/shell_files/upload_transfer_rate.sh
  57. 14 0
      libs/modules/shell_files/user_accounts.sh
  58. 1 0
      libs/timedtask/kpi.go
  59. 16 0
      libs/timedtask/license.go
  60. 1 0
      libs/timedtask/timedtask.go
  61. 9875 0
      logs/error.log
  62. 87 0
      main.go
  63. 45 0
      public/20160321
  64. 232 0
      public/application.html
  65. 350 0
      public/basic-info.html
  66. BIN
      public/favicon.ico
  67. 342 0
      public/index.html
  68. 311 0
      public/network.html
  69. 14480 0
      public/static/css/components-rounded.css
  70. 19 0
      public/static/css/custom.css
  71. 2428 0
      public/static/css/layout.css
  72. 2570 0
      public/static/css/plugins.css
  73. BIN
      public/static/img/accordion-plusminus.png
  74. BIN
      public/static/img/ajax-loading.gif
  75. BIN
      public/static/img/ajax-modal-loading.gif
  76. BIN
      public/static/img/avatar.png
  77. BIN
      public/static/img/datatable-row-openclose.png
  78. BIN
      public/static/img/input-spinner.gif
  79. BIN
      public/static/img/loading-spinner-blue.gif
  80. BIN
      public/static/img/loading-spinner-default.gif
  81. BIN
      public/static/img/loading-spinner-grey.gif
  82. BIN
      public/static/img/loading.gif
  83. BIN
      public/static/img/logo.jpg
  84. BIN
      public/static/img/logo.png
  85. BIN
      public/static/img/menu-toggler.png
  86. BIN
      public/static/img/overlay-icon.png
  87. BIN
      public/static/img/portlet-collapse-icon-white.png
  88. BIN
      public/static/img/portlet-collapse-icon.png
  89. BIN
      public/static/img/portlet-config-icon-white.png
  90. BIN
      public/static/img/portlet-config-icon.png
  91. BIN
      public/static/img/portlet-expand-icon-white.png
  92. BIN
      public/static/img/portlet-expand-icon.png
  93. BIN
      public/static/img/portlet-reload-icon-white.png
  94. BIN
      public/static/img/portlet-reload-icon.png
  95. BIN
      public/static/img/portlet-remove-icon-white.png
  96. BIN
      public/static/img/portlet-remove-icon.png
  97. BIN
      public/static/img/remove-icon-small.png
  98. BIN
      public/static/img/social/Thumbs.db
  99. BIN
      public/static/img/social/aboutme.png
  100. 0 0
      public/static/img/social/amazon.png

+ 1 - 0
License

@@ -0,0 +1 @@
+W36fR5EjoA0FGfFBqYGqtimZZJTdw3cOlNOm9QD307zlfDkh1TqTU4W1pgLrWALOAcmsAny5iQBCpQLLyulsHq0uQow80UmXKZ0JVLTZaIA=

+ 5 - 0
build.bat

@@ -0,0 +1,5 @@
+@echo off
+echo compiling...
+go build -ldflags -H=windowsgui
+echo Compile complete.
+@pause

+ 25 - 0
config/cfg.ini

@@ -0,0 +1,25 @@
+[http]
+enabled = 1
+ipaddr = 0.0.0.0
+port = 88
+static_path = /public/
+script_path = /libs/modules/shell_files
+
+[tcp]
+ipaddr = 0.0.0.0
+port = 1991
+
+[websocket]
+enabled = 1
+ipaddr = 0.0.0.0
+port = 2016
+
+[ping]
+url = www.baidu.com,www.sina.cn,www.baidu.com,www.sina.cn,www.baidu.com,www.sina.cn,www.sina.cn,www.baidu.com,www.sina.cn,www.baidu.com,www.sina.cn
+count = 2
+
+[process]
+php = /bin/php5/php
+htrd-agent = ./htrd-agent
+test = /usr/libexec/secinitd
+mysqld = /Applications/XAMPP/xamppfiles/sbin/mysqld

+ 117 - 0
control

@@ -0,0 +1,117 @@
+#!/bin/bash
+
+WORKSPACE=$(cd $(dirname $0)/; pwd)
+cd $WORKSPACE
+
+mkdir -p var
+
+module=agent
+app=htrd-$module
+version=1.0
+pidfile=var/agent.pid
+logfile=var/agent.log
+
+function check_pid() {
+    if [ -f $pidfile ];then
+        pid=`cat $pidfile`
+        if [ -n $pid ]; then
+            running=`ps -p $pid|grep -v "PID TTY" |wc -l`
+            return $running
+        fi
+    fi
+    return 0
+}
+
+function start() {
+    check_pid
+    running=$?
+    if [ $running -gt 0 ];then
+        echo -n "$app now is running already, pid="
+        cat $pidfile
+        return 1
+    fi
+
+    nohup ./$app &> $logfile &
+    sleep 1
+    running=`ps -p $! | grep -v "PID TTY" | wc -l`
+    if [ $running -gt 0 ];then
+        echo $! > $pidfile
+        echo "$app started..., pid=$!"
+    else
+        echo "$app failed to start."
+        return 1
+    fi
+}
+
+function stop() {
+    pid=`cat $pidfile`
+    kill $pid
+    rm -f $pidfile
+    echo "$app stoped..."
+}
+
+function restart() {
+    stop
+    sleep 1
+    start
+}
+
+function status() {
+    check_pid
+    running=$?
+    if [ $running -gt 0 ];then
+        echo started
+    else
+        echo stoped
+    fi
+}
+
+function tailf() {
+    tail -f $logfile
+}
+
+function build() {
+    go build
+    if [ $? -ne 0 ]; then
+        exit $?
+    fi
+    mv $module $app
+}
+
+function pack() {
+    build
+    file_list="public control logs i18n config License README.md $app"
+    echo "...tar $app-$version.tar.gz <= $file_list"
+    tar zcf $app-$version.tar.gz $file_list
+}
+
+function packbin() {
+    build
+    tar zcvf $app-bin-$version.tar.gz $app
+}
+
+function help() {
+    echo "$0 build|pack|start|stop|restart|status|tail"
+}
+
+if [ "$1" == "" ]; then
+    help
+elif [ "$1" == "stop" ];then
+    stop
+elif [ "$1" == "start" ];then
+    start
+elif [ "$1" == "restart" ];then
+    restart
+elif [ "$1" == "status" ];then
+    status
+elif [ "$1" == "tail" ];then
+    tailf
+elif [ "$1" == "build" ];then
+    build
+elif [ "$1" == "pack" ];then
+    pack
+elif [ "$1" == "packbin" ];then
+    packbin
+else
+    help
+fi

+ 212 - 0
http/http.go

@@ -0,0 +1,212 @@
+package http
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"strconv"
+	"time"
+
+	"53it.net/agent/libs/collection"
+	"53it.net/agent/libs/common"
+	"53it.net/agent/libs/config"
+)
+
+// 画线数据,每条线数据结构
+type Plot struct {
+	Key   string `json:"key"`
+	Value string `json:"value"`
+}
+
+// 最终数据结构
+type Data struct {
+	State string `json:"state"`
+	Msg   string `json:"msg"`
+	Data  Lists  `json:"data"`
+	Time  string `json:"time"`
+}
+
+// ajax每行内容
+type ListRow interface{}
+
+// ajax列表数据
+type Lists []ListRow
+
+// ajax请求包
+type T struct {
+	ModuleName string `json:"module_name"`
+	Time       string `json:"time"`
+}
+
+// 启动http服务
+func StartHttp() {
+	// 获取配置文件http服务配置
+	listenAddress := config.CFG.Http.Ipaddr + ":" + config.CFG.Http.Port // 启动ip和端口
+	staticPath := common.GetRootDir() + config.CFG.Http.StaticPath       // 静态文件路径
+
+	// 静态文件服务器
+	http.Handle("/", http.FileServer(http.Dir(staticPath)))
+	// ajax请求数据表数据
+	http.HandleFunc("/data/", httpAjaxTableData)
+	// 重置配置文件
+	http.HandleFunc("/config/", httpAjaxConfig)
+
+	fmt.Println("正在启动http服务:", listenAddress)
+	err := http.ListenAndServe(listenAddress, nil)
+	if err != nil {
+		fmt.Println("http服务启动失败:", err)
+		common.LogFile.W(fmt.Sprintf("http服务启动失败:%s", err.Error()), "http", "StartHttp")
+	}
+}
+
+// 处理ajax请求的表格数据
+func httpAjaxTableData(w http.ResponseWriter, r *http.Request) {
+	// 接收参数
+	module := r.URL.Query().Get("module_name")
+	// 当前时间
+	strTime := time.Now().Format("15:04:05")
+	// 最终发送的数据包
+	data := &Data{State: "0", Msg: module, Time: strTime}
+	// 判断是否未传参数
+	if len(module) > 0 {
+		// 根据modelname获取列表数据
+		plot := getDataList(module)
+		data.Data = plot
+	} else {
+		data.State = "1"
+		data.Data = Lists{}
+	}
+	// 转json
+	wdata, err := json.Marshal(data)
+	if err != nil {
+		common.LogFile.E("ajax输出转json失败", "http", "httpAjaxTableData")
+	}
+	// 发送数据
+	w.Write(wdata)
+}
+
+// 配置文件操作
+func httpAjaxConfig(w http.ResponseWriter, r *http.Request) {
+	// 接收参数
+	module := r.URL.Query().Get("handle")
+	// 最终发送的数据包
+	data := &Data{State: "0", Msg: module, Data: Lists{}}
+	if len(module) > 0 {
+		err := config.ResetConfig()
+		if err != nil {
+			data.Msg = "配置文件重置失败"
+		} else {
+			data.Msg = "配置文件已重置"
+		}
+	} else {
+		data.State = "1"
+		data.Msg = "参数错误"
+	}
+	// 转json
+	wdata, err := json.Marshal(data)
+	if err != nil {
+		common.LogFile.E("ajax输出转json失败", "http", "httpAjaxConfig")
+	}
+	// 发送数据
+	w.Write(wdata)
+}
+
+// 获取列表内容
+func getDataList(moduleName string) (plot Lists) {
+	switch moduleName {
+	case "ram_usage":
+		v := collection.GetMemUsageRate()
+		plot = append(plot, Plot{Key: strconv.FormatInt(time.Now().Unix(), 10), Value: fmt.Sprintf("%2f", v)})
+		break
+	case "cpu_utilization":
+		v := collection.GetCPUUsageRate()
+		plot = append(plot, Plot{Key: strconv.FormatInt(time.Now().Unix(), 10), Value: fmt.Sprintf("%2f", v)})
+		break
+	case "cpu_avg_load":
+		v1, v5, v15 := collection.GetLoadAvg()
+		plot = append(plot, Plot{Key: strconv.FormatInt(time.Now().Unix(), 10), Value: fmt.Sprintf("%2f", v1)})
+		plot = append(plot, Plot{Key: strconv.FormatInt(time.Now().Unix(), 10), Value: fmt.Sprintf("%2f", v5)})
+		plot = append(plot, Plot{Key: strconv.FormatInt(time.Now().Unix(), 10), Value: fmt.Sprintf("%2f", v15)})
+		break
+	case "ram_Intensive_processes":
+		rams := collection.GetRAMIntensiveProcesses()
+		for _, v := range rams {
+			plot = append(plot, v)
+		}
+		break
+	case "disk_processes":
+		disks, _ := collection.GetDiskUsages()
+		for _, v := range disks {
+			plot = append(plot, v)
+		}
+		break
+	case "general_info":
+		hostInfo := collection.GetHostInfo()
+		plot = append(plot, hostInfo)
+		break
+	case "mem_info":
+		memInfo := collection.GetMenInfos()
+		plot = append(plot, memInfo)
+		break
+	case "cpu_info":
+		cpuInfo := collection.GetCPUInfos()
+		for _, v := range cpuInfo {
+			plot = append(plot, v)
+		}
+		break
+	case "disk_io_stat":
+		diskIo := collection.GetDiskIOCountersStat()
+		for _, v := range diskIo {
+			plot = append(plot, v)
+		}
+		break
+	case "network_flow":
+		netFlow := collection.GetNetworkFlow()
+		for _, v := range netFlow {
+			plot = append(plot, v)
+		}
+		break
+	case "network_addrs":
+		netAddrs := collection.GetNetworkAddrs()
+		for _, v := range netAddrs {
+			plot = append(plot, v)
+		}
+		break
+	case "ping":
+		pings, err := collection.PingConf()
+		if err == nil {
+			for _, v := range pings {
+				plot = append(plot, v)
+			}
+		}
+		break
+	case "processes_run":
+		runs, err := collection.ChackProcessCmd()
+		if err == nil {
+			for _, v := range runs {
+				plot = append(plot, v)
+			}
+		}
+		break
+	case "network_client_count":
+		netCount := collection.GetNetworkClientCount()
+		plot = append(plot, netCount)
+		break
+	case "disk_io_kbps":
+		diskKbps := collection.GetDiskIOKbps()
+		for _, v := range diskKbps {
+			plot = append(plot, v)
+		}
+		break
+	case "processes_count":
+		count := collection.GetProcessCount()
+		plot = append(plot, count)
+		break
+	}
+
+	if len(plot) == 0 {
+		plot = make(Lists, 0)
+	}
+
+	return plot
+}

+ 61 - 0
http/websocket.go

@@ -0,0 +1,61 @@
+package http
+
+import (
+	"fmt"
+	"net/http"
+	"time"
+
+	"53it.net/agent/libs/common"
+
+	"53it.net/agent/libs/config"
+	"golang.org/x/net/websocket"
+)
+
+// 启动Websocket服务
+func StartWebsocket() {
+	// 监听/json路径
+	http.Handle("/json", websocket.Handler(jsonServer))
+	socketAddress := config.CFG.Websocket.Ipaddr + ":" + config.CFG.Websocket.Port
+	fmt.Println("启动websocket服务:", socketAddress)
+	err := http.ListenAndServe(socketAddress, nil)
+	if err != nil {
+		fmt.Println("websocket服务启动失败:", err)
+		common.LogFile.W(fmt.Sprintf("websocket服务启动失败:%s", err.Error()), "http", "StartWebsocket")
+	}
+}
+
+// websocket 使用json通讯
+func jsonServer(ws *websocket.Conn) {
+	common.LogFile.I("有客户端链接上了websocket", "http", "jsonServer")
+	//	fmt.Println("jsonServer 连接成功")
+	for {
+		// 接收信息转成json数据
+		var msg T
+		err := websocket.JSON.Receive(ws, &msg)
+		if err != nil {
+			common.LogFile.W(fmt.Sprintf("接收数据转失败:%s", err.Error()), "http", "jsonServer")
+			break
+		}
+		//fmt.Printf("recv:%#v\n", msg)
+
+		go timedTask(ws, msg) // 处理一个表格数据-开一个协程
+	}
+}
+
+// 定时发送数据到客户端
+func timedTask(ws *websocket.Conn, msg T) {
+	// 根据modelname获取列表数据
+	plot := getDataList(msg.ModuleName)
+	// 当前时间
+	strTime := time.Now().Format("15:04:05")
+	// 最终发送的数据包
+	data := &Data{State: "0", Msg: msg.ModuleName, Data: plot, Time: strTime}
+	err := websocket.JSON.Send(ws, data)
+	if err != nil {
+		common.LogFile.W(fmt.Sprintf("发送数据转失败:%s", err.Error()), "http", "timedTask")
+		fmt.Println(err)
+		ws.Close()
+		return
+	}
+	return
+}

+ 13 - 0
i18n/en_US.json

@@ -0,0 +1,13 @@
+{
+    "main.title" : "CutleryPlus",
+    "main.subtitle" : "Knives that put cut in cutlery.",
+    "menu" : {
+    	"home" : "Home",
+    	"products": {
+    		"self": "Products",
+    		"forks" : "Forks",
+    		"knives" : "Knives",
+    		"spoons" : "Spoons"
+    	}
+    }
+}

+ 0 - 0
i18n/zh-CN.json


+ 4 - 0
libs/collection/collection.go

@@ -0,0 +1,4 @@
+package collection
+
+func init() {
+}

+ 46 - 0
libs/collection/cpuinfo.go

@@ -0,0 +1,46 @@
+package collection
+
+import (
+	"runtime"
+	"strconv"
+	"time"
+
+	"53it.net/agent/libs/common"
+	"github.com/shirou/gopsutil/cpu"
+)
+
+// cpu 利用率
+func GetCPUUsageRate() float64 {
+	c, err := cpu.CPUTimes(false)
+	if err != nil {
+		common.LogFile.W("计算cpu使用率,获取内存信息失败", "cpuinfo", "GetCPUUsageRate")
+		return 0.0
+	}
+	// 获取两次数据求差
+	cc := c[0]
+	idel1 := cc.Idle
+	total1 := cc.Idle + cc.Guest + cc.GuestNice + cc.Iowait + cc.Irq + cc.Nice + cc.Softirq + cc.Steal + cc.Stolen + cc.System + cc.User
+	// 睡1秒
+	time.Sleep(1 * time.Second)
+	c, _ = cpu.CPUTimes(false)
+	cc = c[0]
+	idel2 := c[0].Idle
+	tota2 := cc.Idle + cc.Guest + cc.GuestNice + cc.Iowait + cc.Irq + cc.Nice + cc.Softirq + cc.Steal + cc.Stolen + cc.System + cc.User
+
+	return (1000*((tota2-total1)-(idel2-idel1))/(tota2-total1) + 5) / 10
+}
+
+// cpu核心数
+func CpuNum() string {
+	return strconv.Itoa(runtime.NumCPU())
+}
+
+// 获取cpu信息
+func GetCPUInfos() []cpu.CPUInfoStat {
+	cpuInfo, err := cpu.CPUInfo()
+	if err != nil {
+		common.LogFile.W("获取内存信息失败", "meninfo", "GetMenInfos")
+		return nil
+	}
+	return cpuInfo
+}

+ 84 - 0
libs/collection/disk.go

@@ -0,0 +1,84 @@
+package collection
+
+import (
+	"strconv"
+	"time"
+
+	"53it.net/agent/libs/common"
+	"github.com/shirou/gopsutil/disk"
+)
+
+type Disk struct {
+	Name              string `json:"name"`
+	Path              string `json:"path"`
+	Total             string `json:"total"`
+	Free              string `json:"free"`
+	Used              string `json:"used"`
+	UsedPercent       string `json:"used_percent"`
+	InodesUsedPercent string `json:"inodes_used_percent"`
+}
+
+type DiskIO struct {
+	Name       string `json:"name"`
+	ReadBytes  uint64 `json:"read_bytes"`
+	WriteBytes uint64 `json:"write_bytes"`
+	ReadCount  uint64 `json:"read_count"`
+	WriteCount uint64 `json:"write_count"`
+}
+
+// 获取各磁盘分区使用率
+func GetDiskUsages() ([]Disk, error) {
+	dList, err := disk.DiskPartitions(true)
+	if err != nil {
+		common.LogFile.W("磁盘使用率获取失败,磁盘列表", "disk", "GetDiskUsages")
+		return nil, err
+	}
+	// 定义返回数组
+	var diskList []Disk
+	for _, v := range dList {
+		dUsage, err := disk.DiskUsage(v.Mountpoint)
+		if err != nil {
+			continue
+		}
+		d := Disk{Name: v.Device, Path: v.Mountpoint, Total: common.FormatUnit(dUsage.Total), Free: common.FormatUnit(dUsage.Free), Used: common.FormatUnit(dUsage.Used), UsedPercent: strconv.FormatFloat(dUsage.UsedPercent, 'g', 5, 32), InodesUsedPercent: strconv.FormatFloat(dUsage.InodesUsedPercent, 'g', 5, 32)}
+		diskList = append(diskList, d)
+	}
+	return diskList, nil
+}
+
+// 获取磁盘读写速率
+func GetDiskIOCountersStat() map[string]disk.DiskIOCountersStat {
+	diskIo, err := disk.DiskIOCounters()
+	if err != nil {
+		common.LogFile.W("磁盘IO获取失败", "disk", "GetDiskIOCountersStat")
+		return nil
+	}
+	return diskIo
+}
+
+// shi shi disk du xie
+func GetDiskIOKbps() []DiskIO {
+	diskIo1, err := disk.DiskIOCounters()
+	if err != nil {
+		common.LogFile.W("磁盘IO获取失败", "disk", "GetDiskIOKbps")
+		return nil
+	}
+	// 停一秒
+	time.Sleep(1 * time.Second)
+	diskIo2, err := disk.DiskIOCounters()
+	// ji suan mei miao du xie shu
+	var diskList []DiskIO
+	for _, v := range diskIo1 {
+		for _, vv := range diskIo2 {
+			if v.Name == vv.Name {
+				diskOne := DiskIO{Name: v.Name, ReadCount: vv.ReadCount, WriteCount: vv.WriteCount}
+				// ji suan cha zhi
+				diskOne.ReadBytes = vv.ReadBytes - v.ReadBytes
+				diskOne.WriteBytes = vv.WriteBytes - v.WriteBytes
+				// zhui jia dao shu zu
+				diskList = append(diskList, diskOne)
+			}
+		}
+	}
+	return diskList
+}

+ 15 - 0
libs/collection/host.go

@@ -0,0 +1,15 @@
+package collection
+
+import (
+	"53it.net/agent/libs/common"
+	"github.com/shirou/gopsutil/host"
+)
+
+func GetHostInfo() *host.HostInfoStat {
+	info, err := host.HostInfo()
+	if err != nil {
+		common.LogFile.W("获取系统基本信息失败", "host", "GetHostInfo")
+		return nil
+	}
+	return info
+}

+ 19 - 0
libs/collection/load.go

@@ -0,0 +1,19 @@
+package collection
+
+import (
+	"runtime"
+
+	"53it.net/agent/libs/common"
+	"github.com/shirou/gopsutil/load"
+)
+
+// 内存使用率
+func GetLoadAvg() (float64, float64, float64) {
+	loadinfo, err := load.LoadAvg()
+	if err != nil {
+		common.LogFile.W("获取1,5,15分钟平均负载失败", "load", "GetLoadAvg")
+		return 0.0, 0.0, 0.0
+	}
+	numberOfCores := float64(runtime.NumCPU()) // cpu核心数
+	return loadinfo.Load1 * 100 / numberOfCores, loadinfo.Load5 * 100 / numberOfCores, loadinfo.Load15 * 100 / numberOfCores
+}

+ 36 - 0
libs/collection/meminfo.go

@@ -0,0 +1,36 @@
+package collection
+
+import (
+	"53it.net/agent/libs/common"
+	"github.com/shirou/gopsutil/mem"
+)
+
+// 内存使用率
+func GetMemUsageRate() float64 {
+	meminfo, err := mem.VirtualMemory()
+	if err != nil {
+		common.LogFile.W("计算内存使用率,获取内存信息失败", "meninfo", "GetMemUsageRate")
+		return 0.0
+	}
+	return meminfo.UsedPercent
+}
+
+// 后去内存大小
+func GetMenSize() (uint64, error) {
+	meminfo, err := mem.VirtualMemory()
+	if err != nil {
+		common.LogFile.W("获取内存大小失败", "meninfo", "GetMenSize")
+		return 0, err
+	}
+	return meminfo.Total, nil
+}
+
+// 获取内存基本信息
+func GetMenInfos() *mem.VirtualMemoryStat {
+	meminfo, err := mem.VirtualMemory()
+	if err != nil {
+		common.LogFile.W("获取内存信息失败", "meninfo", "GetMenInfos")
+		return nil
+	}
+	return meminfo
+}

+ 82 - 0
libs/collection/network.go

@@ -0,0 +1,82 @@
+package collection
+
+import (
+	"time"
+
+	"53it.net/agent/libs/common"
+
+	"github.com/shirou/gopsutil/net"
+)
+
+type NetFlow struct {
+	Name      string `json:"name"`
+	BytesSent uint64 `json:"bytes_sent"`
+	BytesRecv uint64 `json:"bytes_recv"`
+}
+
+type NetAddr struct {
+	Name  string                 `json:"name"`
+	Addrs []net.NetInterfaceAddr `json:"addrs"`
+	RX    uint64                 `json:"rx"` // 发出数据包
+	TX    uint64                 `json:"tx"` // 接收数据包
+}
+
+// 网络流量
+func GetNetworkFlow() []NetFlow {
+	netFlow, err := net.NetIOCounters(true)
+	if err != nil {
+		common.LogFile.W("获取网络流量失败", "network", "GetNetworkFlow")
+		return nil
+	}
+	// 停一秒
+	time.Sleep(1 * time.Second)
+	netFlow1, err := net.NetIOCounters(true)
+	// 计算流量
+	var netFlowList []NetFlow
+
+	for k, v := range netFlow {
+		for _, vv := range netFlow1 {
+			if v.Name == vv.Name {
+				sent := netFlow1[k].BytesSent - v.BytesSent
+				recv := netFlow1[k].BytesRecv - v.BytesRecv
+				netFlowList = append(netFlowList, NetFlow{Name: v.Name, BytesSent: sent, BytesRecv: recv})
+			}
+		}
+	}
+	return netFlowList
+}
+
+// 获取网卡喝ip地址流量信息
+func GetNetworkAddrs() []NetAddr {
+	netAddrs, err := net.NetIOCounters(true)
+	if err != nil {
+		common.LogFile.W("获取网卡基本信息失败", "network", "GetNetworkAddrs")
+		return nil
+	}
+	// 获取网卡信息
+	netInfos, _ := net.NetInterfaces()
+	// 网卡信息
+	var netAddrList []NetAddr
+	var oneNetAddr NetAddr
+	for _, v := range netAddrs {
+		oneNetAddr = NetAddr{Name: v.Name, RX: v.PacketsSent, TX: v.PacketsRecv}
+		// 获取IP地址
+		for _, vv := range netInfos {
+			if vv.Name == v.Name {
+				oneNetAddr.Addrs = vv.Addrs
+			}
+		}
+		netAddrList = append(netAddrList, oneNetAddr)
+	}
+	return netAddrList
+}
+
+// 获取网络连接数
+func GetNetworkClientCount() int {
+	netList, err := net.NetConnections("all")
+	if err != nil {
+		common.LogFile.W("获取网络连接数", "network", "GetNetworkClientCount")
+		return 0
+	}
+	return len(netList)
+}

+ 166 - 0
libs/collection/ping.go

@@ -0,0 +1,166 @@
+package collection
+
+import (
+	"errors"
+	"fmt"
+	"net"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+
+	"53it.net/agent/libs/common"
+	"53it.net/agent/libs/config"
+)
+
+type PingTime struct {
+	Host  string `json:"host"`
+	Total string `json:"total"`
+	Min   string `json:"min"`
+	Max   string `json:"max"`
+	Avg   string `json:"avg"`
+}
+
+// ping 配置文件
+func PingConf() ([]PingTime, error) {
+	urls := strings.Split(config.CFG.Ping.Url, ",")
+	if len(urls) < 1 {
+		common.LogFile.W("未配置ping主机", "ping", "PingConf")
+		return nil, errors.New("未配置ping主机")
+	}
+	// ping次数
+	count, err := strconv.Atoi(config.CFG.Ping.Count)
+	if err != nil {
+		count = 2
+	}
+	// 定义返回数据
+	var pings []PingTime
+	// 并发ping主机
+	c := make(chan PingTime, len(urls))
+	for _, v := range urls {
+		go func(v string) {
+			var p PingTime
+			p, err := Ping(v, count)
+			if err != nil {
+				return
+			}
+			p.Host = v
+			c <- p
+		}(v)
+	}
+	// 取值
+	for i := 0; i < len(urls); i++ {
+		pings = append(pings, <-c)
+	}
+
+	return pings, nil
+}
+
+// ping 主机名和次数
+func Ping(host string, numPings int) (PingTime, error) {
+	rAddr, err := net.ResolveIPAddr("ip4", host)
+	if err != nil {
+		return PingTime{}, err
+	}
+
+	conn, err := net.DialIP("ip4:icmp", nil, rAddr)
+	if err != nil {
+		return PingTime{}, err
+	}
+	defer conn.Close()
+
+	pid := os.Getpid()
+	var id1 = byte(pid & 0xff00 >> 8)
+	var id2 = byte(pid & 0xff)
+
+	var timeout = 1 * time.Second
+	var interval = 1 * time.Second
+	var messageLength = 64
+
+	pingTimes := []time.Duration{}
+	for i := 0; i < numPings; i++ {
+		msg := MakeEchoRequest(i, messageLength, id1, id2)
+
+		startTime := time.Now()
+		deadline := startTime.Add(timeout)
+		conn.SetDeadline(deadline)
+
+		if _, err = conn.Write(msg[0:messageLength]); err != nil {
+			continue
+		}
+
+		response := make([]byte, 64)
+		for {
+			_, _, err := conn.ReadFrom(response)
+			if err != nil {
+				return PingTime{}, err
+				break
+			}
+			if response[0] == 0 {
+				duration := time.Since(startTime)
+				pingTimes = append(pingTimes, duration)
+			}
+			break
+		}
+		time.Sleep(interval)
+	}
+
+	total, min, max, avg := ComputeStats(pingTimes)
+
+	return PingTime{Total: fmt.Sprintf("%v", total), Min: fmt.Sprintf("%v", min), Max: fmt.Sprintf("%v", max), Avg: fmt.Sprintf("%v", avg)}, nil
+}
+
+func CheckSum(buf []byte) uint16 {
+	var sum uint32
+	for i := 0; i < len(buf)-1; i += 2 {
+		sum += uint32(buf[i+1])<<8 | uint32(buf[i])
+	}
+
+	// Take care of left over byte
+	if len(buf)%2 != 0 {
+		sum += uint32(buf[len(buf)-1])
+	}
+
+	sum = (sum >> 16) + (sum & 0xffff)
+	sum = sum + (sum >> 16)
+	return uint16(^sum)
+}
+
+func MakeEchoRequest(seqNo int, length int, id1 byte, id2 byte) [512]byte {
+	var msg [512]byte
+	// ICMP v4 echo request is 8
+	msg[0] = 8
+	// Code is always 0
+	msg[1] = 0
+	// Zero checksum (will be overwritten shortly)
+	msg[2] = 0
+	msg[3] = 0
+	// Id
+	msg[4] = id1
+	msg[5] = id2
+	// Not sure about this one..
+	msg[6] = 0
+	msg[7] = byte(seqNo)
+	// Generate the checksum and insert into message
+	check := CheckSum(msg[0:length])
+	msg[2] = byte(check & 0xff)
+	msg[3] = byte(check >> 8)
+	return msg
+}
+
+func ComputeStats(durations []time.Duration) (time.Duration, time.Duration, time.Duration, time.Duration) {
+	var total time.Duration
+	min := durations[0]
+	max := durations[0]
+	for _, duration := range durations {
+		total += duration
+		if duration > max {
+			max = duration
+		}
+		if duration < min {
+			min = duration
+		}
+	}
+
+	return total, min, max, total / time.Duration(len(durations))
+}

+ 47 - 0
libs/collection/process.go

@@ -0,0 +1,47 @@
+package collection
+
+import (
+	"time"
+
+	"github.com/shirou/gopsutil/process"
+
+	"53it.net/agent/libs/common"
+)
+
+type ProcessesPercent struct {
+	Pid        int32   `json:"pid"`
+	User       string  `json:"user"`
+	MEMPercent float32 `json:"mem_percent"`
+	CPUPercent float32 `json:"cpu_percent"`
+	Rss        uint64  `json:"rss"`
+	Vsz        uint64  `json:"vsz"`
+	Cmd        string  `json:"cmd"`
+	Swap       uint64  `json:"swap"`
+}
+
+type ProcessRun struct {
+	Name     string `json:"name"`
+	Location string `json:"location"`
+	Run      bool   `json:"run"`
+	Count    int    `json:"count"`
+}
+
+type Win32ProcessesPercent struct {
+	Name           string     `json:"name"`
+	ExecutablePath *string    `json:"executable_path"`
+	CommandLine    *string    `json:"command_line"`
+	Priority       uint32     `json:"priority"`
+	CreationDate   *time.Time `json:"creation_date"`
+	ProcessId      uint32     `json:"process_id"`
+	ThreadCount    uint32     `json:"thread_count"`
+}
+
+// 进程数
+func GetProcessCount() int {
+	ret, err := process.Pids()
+	if err != nil {
+		common.LogFile.W("获取进程数失败", "process", "GetProcessCount")
+		return 0
+	}
+	return len(ret)
+}

+ 128 - 0
libs/collection/process_unix.go

@@ -0,0 +1,128 @@
+// +build linux freebsd darwin
+
+package collection
+
+import (
+	"strconv"
+	"strings"
+
+	"53it.net/agent/libs/common"
+	"53it.net/agent/libs/config"
+
+	"github.com/shirou/gopsutil/process"
+)
+
+// 获取进程内存CPU使用率
+func GetRAMIntensiveProcesses() []ProcessesPercent {
+	ret, err := process.Pids()
+	if err != nil {
+		common.LogFile.W("获取进程pid列表失败", "process", "GetRAMIntensiveProcesses")
+		return nil
+	}
+	// 总内存大小
+	MemTotal, _ := GetMenSize()
+	// pid cpu使用率
+	pidsPercent, _ := getPidCpuPercent()
+	// 最终显示数据
+	var memdata []ProcessesPercent
+	// 循环读取需要展示的信息
+	for _, v := range ret {
+		proc, err := process.NewProcess(v)
+		if err != nil {
+			common.LogFile.W("视图根据pid创建对象失败", "process", "GetRAMIntensiveProcesses")
+			break
+		}
+		// 用于保存每一行信息
+		row := ProcessesPercent{Pid: v}
+		// 获取用户
+		username, _ := proc.Username()
+		row.User = username
+		// 获取内存使用情况
+		meminfo, err := proc.MemoryInfo()
+		if err != nil {
+			continue
+		}
+
+		row.Rss = meminfo.RSS
+		row.Vsz = meminfo.VMS
+		row.Swap = meminfo.Swap
+		row.MEMPercent = float32(row.Rss) / float32(MemTotal) * 100
+		row.CPUPercent, _ = pidsPercent[v] //getPidCpuPercent(v) // 自己实现后去cpu使用率
+		// 获取cmd信息
+		cmd, err := proc.Cmdline()
+		if err != nil {
+			row.Cmd = "-"
+		}
+		row.Cmd = cmd
+		// 添加到数组
+		memdata = append(memdata, row)
+	}
+
+	return memdata
+}
+
+// 检查进程是否存活
+func ChackProcessCmd() ([]ProcessRun, error) {
+	chackProcessList, err := config.Options("process")
+	if err != nil {
+		common.LogFile.W("检查进程存活,获取配置文件要检查进程失败", "process_unix", "ChackProcessCmd")
+		return nil, err
+	}
+	// 这里借用内存进程占用函数
+	processList := GetRAMIntensiveProcesses()
+	// 验证对应进程是否存活
+	var processRunList []ProcessRun
+	for _, v := range chackProcessList {
+		cmd, err := config.String("process", v)
+		if err != nil {
+			continue
+		}
+		// 单个进程基本信息
+		pRun := ProcessRun{Name: v, Location: cmd, Count: 0}
+		// 检查存活
+		isRun := false
+		// 进程计数
+		var runNumber = 0
+		for _, vv := range processList {
+			if strings.Index(vv.Cmd, cmd) == 0 {
+				isRun = true
+				runNumber++
+			}
+		}
+		pRun.Run = isRun
+		pRun.Count = runNumber
+		processRunList = append(processRunList, pRun)
+	}
+	return processRunList, nil
+}
+
+func getPidCpuPercent() (map[int32]float32, error) {
+	cmd := []string{"-x", "-o", "pid %cpu"}
+	percent, err := common.Exec("/bin/ps", cmd...)
+	if err != nil {
+		common.LogFile.W("unix获取cpu使用率失败", err, "process_unix", "getPidCpuPercent")
+		return nil, err
+	}
+	// cpu核心数转float
+	cpuNumber, err := strconv.ParseFloat(CpuNum(), 32)
+	if err != nil {
+		cpuNumber = 1.0
+	}
+	// 回车切分数据
+	lines := strings.Split(string(percent), "\n")
+	// 组织pid对cpu的使用率
+	pidsPercent := make(map[int32]float32)
+	for _, v := range lines[1:] {
+		v = strings.Trim(v, " ")
+		vv := strings.Split(v, " ")
+		if len(vv) < 2 {
+			continue
+		}
+		pid, _ := strconv.Atoi(vv[0]) // pid做下标
+		percentFloat, _ := strconv.ParseFloat(vv[len(vv)-1], 64)
+		value := percentFloat / cpuNumber
+		pidsPercent[int32(pid)] = float32(value)
+	}
+
+	return pidsPercent, nil
+}

+ 75 - 0
libs/collection/process_windows.go

@@ -0,0 +1,75 @@
+// +build windows
+
+package collection
+
+import (
+	"strings"
+
+	"53it.net/agent/libs/common"
+	"53it.net/agent/libs/config"
+
+	"github.com/shirou/gopsutil/process"
+)
+
+func GetRAMIntensiveProcesses() []Win32ProcessesPercent {
+	ret, err := process.Pids()
+	if err != nil {
+		common.LogFile.W("获取进程pid列表失败", "process_windows", "GetRAMIntensiveProcesses")
+		return nil
+	}
+	// 最终显示数据
+	var memdata []Win32ProcessesPercent
+	// 循环读取需要展示的信息
+	for _, v := range ret {
+		proc, err := process.GetWin32Proc(v)
+		if err != nil {
+			common.LogFile.W("获取win32进程信息失败", "process_windows", "GetRAMIntensiveProcesses")
+			continue
+		}
+		row := Win32ProcessesPercent{
+			Name:           proc[0].Name,
+			ExecutablePath: proc[0].ExecutablePath,
+			CommandLine:    proc[0].CommandLine,
+			Priority:       proc[0].Priority,
+			CreationDate:   proc[0].CreationDate,
+			ProcessId:      proc[0].ProcessId,
+			ThreadCount:    proc[0].ThreadCount,
+		}
+		memdata = append(memdata, row)
+	}
+	return memdata
+}
+
+func ChackProcessCmd() ([]ProcessRun, error) {
+	chackProcessList, err := config.Options("process")
+	if err != nil {
+		common.LogFile.W("检查进程存活,获取配置文件要检查进程失败", "process_windows", "ChackProcessCmd")
+		return nil, err
+	}
+	// 这里借用内存进程占用函数
+	processList := GetRAMIntensiveProcesses()
+	// 验证对应进程是否存活
+	var processRunList []ProcessRun
+	for _, v := range chackProcessList {
+		cmd, err := config.String("process", v)
+		if err != nil {
+			continue
+		}
+		// 单个进程基本信息
+		pRun := ProcessRun{Name: v, Location: cmd, Count: 0}
+		// 检查存活
+		isRun := false
+		// 进程计数
+		var runNumber = 0
+		for _, vv := range processList {
+			if strings.Index(*vv.ExecutablePath, cmd) == 0 {
+				isRun = true
+				runNumber++
+			}
+		}
+		pRun.Run = isRun
+		pRun.Count = runNumber
+		processRunList = append(processRunList, pRun)
+	}
+	return processRunList, nil
+}

+ 106 - 0
libs/collection/stat.go

@@ -0,0 +1,106 @@
+package collection
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"strconv"
+	"strings"
+
+	"53it.net/agent/libs/common"
+)
+
+type CpuSnapshoot struct {
+	User     uint64 // 用户态的CPU时间(单位:jiffies)
+	Nice     uint64 // nice值为负的进程所占用的CPU时间(单位:jiffies)
+	System   uint64 // 核心时间(单位:jiffies)
+	Idle     uint64 // 除硬盘IO等待时间以外其它等待时间(单位:jiffies)
+	Iowait   uint64 // 硬盘IO等待时间(单位:jiffies)
+	Irq      uint64 // 硬中断时间(单位:jiffies)  (since  2.6.0-test4)
+	SoftIrq  uint64 // 软中断时间(单位:jiffies) (since 2.6.0-test4)
+	Steal    uint64 // time spent in other OSes when running in a virtualized environment
+	Guest    uint64 // 在内核控制下运行一个虚拟的操作系统的虚拟机 time spent running a virtual CPU for guest operating systems under the control of the Linux kernel.
+	Total    uint64 // 总时间
+	Switches uint64 // 自系统启动以来CPU发生的上下文交换的次数
+}
+
+// 获取用户,系统,空闲,等待 使用率
+func GetStatUsageRate() (user, system, idel, softirq string) {
+	stat, err := CpuSnapShoot()
+	if err != nil {
+		return
+	}
+	user = fmt.Sprintf("%.2f", stat.User/stat.Total*100)
+	system = fmt.Sprintf("%.2f", stat.System/stat.Total*100)
+	idel = fmt.Sprintf("%.2f", stat.Idle/stat.Total*100)
+	softirq = fmt.Sprintf("%.2f", stat.SoftIrq/stat.Total*100)
+	return user, system, idel, softirq
+}
+
+func CpuSnapShoot() (*CpuSnapshoot, error) {
+	contents, err := ioutil.ReadFile("/proc/stat")
+	if err != nil {
+		common.LogFile.W("进程使用率信息读取失败", "stat", "CpuSnapShoot")
+		return nil, err
+	}
+	// 系统进程使用率
+	s := &CpuSnapshoot{}
+	reader := bufio.NewReader(bytes.NewBuffer(contents))
+	for {
+		line, _, err := reader.ReadLine()
+		if err == io.EOF {
+			break
+		}
+		// 用空格分割成数组
+		fields := strings.Fields(string(line))
+		if len(fields) > 0 {
+			fieldName := fields[0]
+			if fieldName == "cpu" {
+				parseCPUFields(fields, s)
+			}
+			// 自系统启动以来CPU发生的上下文交换的次数
+			if fieldName == "ctxt" {
+				s.Switches, err = strconv.ParseUint(fields[1], 10, 64)
+				if err != nil {
+					continue
+				}
+			}
+		}
+	}
+	return s, nil
+}
+
+// 分出用户系统等使用情况
+func parseCPUFields(fields []string, stat *CpuSnapshoot) {
+	numFields := len(fields)
+	for i := 1; i < numFields; i++ {
+		val, err := strconv.ParseUint(fields[i], 10, 64)
+		if err != nil {
+			continue
+		}
+
+		stat.Total += val
+		switch i {
+		case 1:
+			stat.User = val
+		case 2:
+			stat.Nice = val
+		case 3:
+			stat.System = val
+		case 4:
+			stat.Idle = val
+		case 5:
+			stat.Iowait = val
+		case 6:
+			stat.Irq = val
+		case 7:
+			stat.SoftIrq = val
+		case 8:
+			stat.Steal = val
+		case 9:
+			stat.Guest = val
+		}
+	}
+}

+ 92 - 0
libs/common/aes.go

@@ -0,0 +1,92 @@
+package common
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+)
+
+type AesEncrypt struct {
+}
+
+const (
+	aesKey = "4561234567890123"
+)
+
+func (this *AesEncrypt) getKey(strKey string) []byte {
+	keyLen := len(strKey)
+	if keyLen < 16 {
+		strKey = aesKey
+	}
+	arrKey := []byte(strKey)
+	if keyLen >= 32 {
+		// 取前32个字节
+		return arrKey[:32]
+	}
+	if keyLen >= 24 {
+		// 取前24个字节
+		return arrKey[:24]
+	}
+	// 取前16个字节
+	return arrKey[:16]
+}
+
+// 加密字符串
+func (this *AesEncrypt) Encrypt(str, keystr string) ([]byte, error) {
+	key := this.getKey(keystr)
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	blockSize := block.BlockSize()
+	strMesg := PKCS7Padding([]byte(str), blockSize)
+	// strMesg = ZeroPadding(strMesg, block.BlockSize())
+	//iv := []byte("1234567890123456")
+	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
+	crypted := make([]byte, len(strMesg))
+	// 根据CryptBlocks方法的说明,如下方式初始化crypted也可以
+	// crypted := strMesg
+	blockMode.CryptBlocks(crypted, strMesg)
+	return crypted, nil
+}
+
+// 解密字符串
+func (this *AesEncrypt) Decrypt(src []byte, keystr string) (strDesc string, err error) {
+	key := this.getKey(keystr)
+
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return "", err
+	}
+	blockSize := block.BlockSize()
+	//iv := []byte("1234567890123456")
+	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
+	origData := make([]byte, len(src))
+	// origData := src
+	blockMode.CryptBlocks(origData, src)
+	origData = UnPKCS7Padding(origData)
+	// origData = ZeroUnPadding(origData)
+	return string(origData), nil
+}
+
+/**
+ *	PKCS7补码
+ *	这里可以参考下http://blog.studygolang.com/167.html
+ */
+func PKCS7Padding(data []byte, blockSize int) []byte {
+	//blockSize := 16
+	padding := blockSize - len(data)%blockSize
+	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
+	return append(data, padtext...)
+
+}
+
+/**
+ *	去除PKCS7的补码
+ */
+func UnPKCS7Padding(data []byte) []byte {
+	length := len(data)
+	// 去掉最后一个字节 unpadding 次
+	unpadding := int(data[length-1])
+	return data[:(length - unpadding)]
+}

+ 102 - 0
libs/common/common.go

@@ -0,0 +1,102 @@
+package common
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strconv"
+	"time"
+)
+
+const (
+	Version  = "1.0"
+	UserName = "左秀朋"
+)
+
+// 传入byte数,输出带格式
+func FormatUnit(v uint64) string {
+	if v < 1024 {
+		return strconv.Itoa(int(v)) + "byte"
+	} else if v < 1024*1024 {
+		return strconv.Itoa(int(v/1024)) + "KB"
+	} else if v < 1024*1024*1024 {
+		return strconv.Itoa(int(v/1024/1024)) + "MB"
+	} else if v < 1024*1024*1024*1024 {
+		return strconv.Itoa(int(v/1024/1024/1024)) + "GB"
+	} else {
+		return strconv.Itoa(int(v/1024/1024/1024/1024)) + "TB"
+	}
+}
+
+// 验证许可证信息
+func CheckLicense() {
+	// 读取文件
+	str, err := ioutil.ReadFile(GetRootDir() + "/License")
+	if err != nil {
+		fmt.Println("读取许可证信息失败,程序无法启动")
+		LogFile.E("读取许可证信息失败,程序无法启动", "commom", "CheckLicense")
+		os.Exit(1)
+	}
+	// 解析许可证信息
+	var lic License
+	err = lic.ValidateLicense(string(str))
+	if err != nil {
+		fmt.Println("许可证文件有问题,请联系开发商")
+		LogFile.E("许可证文件有问题,请联系开发商", "commom", "CheckLicense")
+		os.Exit(1)
+	}
+	// 验证版本
+	if lic.Version != Version {
+		fmt.Println("许可证不适用于当前版本")
+		LogFile.E("许可证不适用于当前版本", "commom", "CheckLicense")
+		os.Exit(1)
+	}
+	// 验证用户
+	if lic.Username != UserName {
+		fmt.Println("该许可证文件不适用于该客户")
+		LogFile.E("该许可证文件不适用于该客户", "commom", "CheckLicense")
+		os.Exit(1)
+	}
+	// 验证时间
+	timeInt, err := time.Parse("2006-01-02", lic.DateExpiry)
+	if err != nil {
+		fmt.Println("许可证出现问题,请联系开发商")
+		LogFile.E("许可证出现问题,请联系开发商", "commom", "CheckLicense")
+		os.Exit(1)
+	}
+	// 时间戳比较
+	if time.Now().Unix() > timeInt.Unix() {
+		fmt.Println("许可证过期,请联系开发商")
+		LogFile.E("许可证过期,请联系开发商", "commom", "CheckLicense")
+		os.Exit(1)
+	}
+}
+
+// 写入当前应用根目录
+func WriteRootDir() error {
+	file, err := filepath.Abs(filepath.Dir(os.Args[0]))
+	if err != nil {
+		fmt.Println("获取路径失败")
+		LogFile.E("获取路径失败", "commom", "WriteRootDir")
+		return err
+	}
+	err = ioutil.WriteFile(RootDir, []byte(file), 0666) // 写文件
+	if err != nil {
+		fmt.Println("写文件失败")
+		LogFile.E("写文件失败", "commom", "WriteRootDir")
+		return err
+	}
+	return nil
+}
+
+// 获取程序跟目录
+func GetRootDir() string {
+	str, err := ioutil.ReadFile(RootDir)
+	if err != nil {
+		// 文件不存在获取执行路径
+		file, _ := filepath.Abs(filepath.Dir(os.Args[0]))
+		return file
+	}
+	return string(str)
+}

+ 19 - 0
libs/common/exec.go

@@ -0,0 +1,19 @@
+package common
+
+import (
+	"bytes"
+	"os/exec"
+)
+
+// 执行脚本返回脚本输出值
+func Exec(script string, arg ...string) (out []byte, err error) {
+	cmd := exec.Command(script, arg...)
+	var output bytes.Buffer
+	cmd.Stdout = &output
+	err = cmd.Run()
+	if err != nil {
+		LogFile.W("执行脚本出现错误", "exec", "Exec")
+		return []byte(""), err
+	}
+	return output.Bytes(), nil
+}

+ 51 - 0
libs/common/license.go

@@ -0,0 +1,51 @@
+package common
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+)
+
+type License struct {
+	Username   string `json:"username"`
+	DateExpiry string `json:"date_expiry"`
+	Version    string `json:"version"`
+}
+
+const (
+	base64Table = "123QRSTUabcdVWXYZHijKLAWDCABDstEFGuvwxyzGHIJklmnopqr234560178912"
+)
+
+var aesObj AesEncrypt // aes加密
+
+// 生成许可证
+func (this *License) NewLicense() ([]byte, error) {
+	newLicense, err := json.Marshal(this)
+	if err != nil {
+		return []byte(""), errors.New("生成License失败")
+	}
+	// aes 加密
+	aesLicense, err := aesObj.Encrypt(string(newLicense), "")
+	if err != nil {
+		return []byte(""), errors.New("aes加密失败")
+	}
+	// base64压缩
+	return []byte(base64.StdEncoding.EncodeToString(aesLicense)), nil
+}
+
+// 验证许可证
+func (this *License) ValidateLicense(str string) error {
+	// base64 解密
+	base64License, err := base64.StdEncoding.DecodeString(str)
+	if err != nil {
+		return errors.New("base64 解密失败")
+	}
+	// aes解密
+	aesLicense, err := aesObj.Decrypt(base64License, "")
+	// 转回License结构体
+	err = json.Unmarshal([]byte(aesLicense), this)
+	if err != nil {
+		return errors.New("json 格式非法")
+	}
+	return nil
+}

+ 14 - 0
libs/common/logs.go

@@ -0,0 +1,14 @@
+package common
+
+import (
+	"github.com/aiwuTech/fileLogger"
+)
+
+var (
+	LogFile *fileLogger.FileLogger
+)
+
+func init() {
+	LogFile = fileLogger.NewDefaultLogger(GetRootDir()+"/logs", "error.log")
+	LogFile.SetLogLevel(fileLogger.INFO)
+}

+ 5 - 0
libs/common/rootdir_unix.go

@@ -0,0 +1,5 @@
+// +build linux freebsd darwin
+
+package common
+
+var RootDir = "/etc/htrd-agent.cfg"

+ 5 - 0
libs/common/rootdir_windows.go

@@ -0,0 +1,5 @@
+// +build windows
+
+package common
+
+var RootDir = "C:\\htrd-agent.cfg"

+ 116 - 0
libs/config/config.go

@@ -0,0 +1,116 @@
+package config
+
+import (
+	"os"
+
+	"53it.net/agent/libs/common"
+	"github.com/larspensjo/config"
+)
+
+type Http struct {
+	Enabled    string
+	Ipaddr     string
+	Port       string
+	StaticPath string
+	ScriptPath string
+}
+
+type Tcp struct {
+	Ipaddr string
+	Port   string
+}
+
+type Websocket struct {
+	Enabled string
+	Ipaddr  string
+	Port    string
+}
+
+type Ping struct {
+	Url   string
+	Count string
+}
+
+type Config struct {
+	Cfg       *config.Config
+	Http      Http
+	Tcp       Tcp
+	Websocket Websocket
+	Ping      Ping
+}
+
+var configFile string = "./config/cfg.ini"
+var CFG Config
+
+func init() {
+	//	fileStr := filepath.Dir(os.Args[0])
+	//	configFile = fmt.Sprint(fileStr, "/config/cfg.ini")
+	configFile = common.GetRootDir() + "/config/cfg.ini" // 绝对路径配置文件地址
+
+	initConfig()
+}
+
+// 初始化配置文件
+func initConfig() {
+	// 设置配置文件
+	cfg, err := config.ReadDefault(configFile)
+	if err != nil {
+		common.LogFile.E("配置文件读取失败")
+		os.Exit(1)
+	}
+	/* 保存配置信息便于调用 */
+	getConfig := func(section string, option string) string {
+		str, err := cfg.String(section, option)
+		if err != nil {
+			return ""
+		}
+		return str
+	}
+	// http 配置
+	http := Http{
+		Enabled:    getConfig("http", "enabled"),
+		Ipaddr:     getConfig("http", "ipaddr"),
+		Port:       getConfig("http", "port"),
+		StaticPath: getConfig("http", "static_path"),
+		ScriptPath: getConfig("http", "script_path"),
+	}
+	// TCP配置信息
+	tcp := Tcp{
+		Ipaddr: getConfig("tcp", "ipaddr"),
+		Port:   getConfig("tcp", "port"),
+	}
+	// websocket配置文件
+	websocket := Websocket{
+		Enabled: getConfig("websocket", "enabled"),
+		Ipaddr:  getConfig("websocket", "ipaddr"),
+		Port:    getConfig("websocket", "port"),
+	}
+	// ping配置
+	ping := Ping{
+		Url:   getConfig("ping", "url"),
+		Count: getConfig("ping", "count"),
+	}
+	// 配置信息
+	CFG = Config{Cfg: cfg, Http: http, Tcp: tcp, Websocket: websocket, Ping: ping}
+}
+
+// 重置config
+func ResetConfig() error {
+	initConfig()
+	return nil
+}
+
+// 分组列表
+func Sections() []string {
+	return CFG.Cfg.Sections()
+}
+
+// 分组下健值对
+func Options(section string) ([]string, error) {
+	return CFG.Cfg.Options(section)
+}
+
+// 获取string值
+func String(section, option string) (string, error) {
+	return CFG.Cfg.String(section, option)
+}

+ 2 - 0
libs/modules/config/ping_hosts

@@ -0,0 +1,2 @@
+baidu.com
+sina.cn

+ 17 - 0
libs/modules/shell_files/arp_cache.sh

@@ -0,0 +1,17 @@
+#!/bin/bash
+
+arpCommand=$(command -v arp) 
+
+result=$($arpCommand | awk 'BEGIN {print "["} NR>1 \
+						{print "{ \"address\": \"" $1 "\", " \
+									"\"hw_type\": \"" $2 "\", " \
+									"\"hw_address\": \"" $3 "\", " \
+									"\"flags\": \"" $4 "\", " \
+									"\"mask\": \"" $5 "\" }, " \
+									} \
+					END {print "]"}' \
+			| /bin/sed 'N;$s/},/}/;P;D')
+
+if [ -z "$result" ];  then echo {}
+else echo $result
+fi 

+ 6 - 0
libs/modules/shell_files/bandwidth.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+/bin/cat /proc/net/dev \
+| awk 'BEGIN {print "["} NR>2 {print "{ \"interface\": \"" $1 "\"," \
+					" \"tx\": " $2 "," \
+					" \"rx\": " $10 " }," } END {print "]"}' \
+| /bin/sed 'N;$s/,\n/\n/;P;D'

+ 11 - 0
libs/modules/shell_files/common_applications.sh

@@ -0,0 +1,11 @@
+#!/bin/bash
+result=$(whereis php node mysql mongo vim python ruby java apache2 nginx openssl vsftpd make \
+| awk -F: '{if(length($2)==0) { installed="false"; } else { installed="true"; } \
+			print \
+			"{ \
+				\"binary\": \""$1"\", \
+				\"location\": \""$2"\", \
+				\"installed\": "installed" \
+			},"}')
+
+echo "[" ${result%?} "]"

+ 7 - 0
libs/modules/shell_files/cpu_info.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+
+result=$(/usr/bin/lscpu \
+		| /usr/bin/awk -F: '{print "\""$1"\": \""$2"\"," }	'\
+		)
+
+echo "{" ${result%?} "}"

+ 13 - 0
libs/modules/shell_files/cpu_intensive_processes.sh

@@ -0,0 +1,13 @@
+#!/bin/bash
+
+result=$(/bin/ps axo pid,user,pcpu,rss,vsz,comm --sort -pcpu,-rss,-vsz \
+			| head -n 15 \
+			| /usr/bin/awk 'BEGIN{OFS=":"} NR>1 {print "{ \"pid\": " $1 \
+							", \"user\": \"" $2 "\"" \
+							", \"cpu%\": " $3 \
+							", \"rss\": " $4 \
+							", \"vsz\": " $5 \
+							", \"cmd\": \"" $6 "\"" "},"\
+						}')
+
+echo "[" ${result%?} "]"

+ 33 - 0
libs/modules/shell_files/cpu_utilization.sh

@@ -0,0 +1,33 @@
+#!/bin/bash
+# by Paul Colby (http://colby.id.au), no rights reserved ;)
+
+PREV_TOTAL=0
+PREV_IDLE=0
+iteration=0
+
+while [[ iteration -lt 2 ]]; do
+  # Get the total CPU statistics, discarding the 'cpu ' prefix.
+  CPU=(`sed -n 's/^cpu\s//p' /proc/stat`)
+  IDLE=${CPU[3]} # Just the idle CPU time.
+
+  # Calculate the total CPU time.
+  TOTAL=0
+  for VALUE in "${CPU[@]}"; do
+    let "TOTAL=$TOTAL+$VALUE"
+  done
+
+  # Calculate the CPU usage since we last checked.
+  let "DIFF_IDLE=$IDLE-$PREV_IDLE"
+  let "DIFF_TOTAL=$TOTAL-$PREV_TOTAL"
+  let "DIFF_USAGE=(1000*($DIFF_TOTAL-$DIFF_IDLE)/$DIFF_TOTAL+5)/10"
+  #echo -en "\rCPU: $DIFF_USAGE%  \b\b"
+
+  # Remember the total and idle CPU times for the next check.
+  PREV_TOTAL="$TOTAL"
+  PREV_IDLE="$IDLE"
+
+  # Wait before checking again.
+  sleep 1
+  iteration="$iteration+1"
+done
+echo -en "$DIFF_USAGE"

+ 18 - 0
libs/modules/shell_files/cron_history.sh

@@ -0,0 +1,18 @@
+#!/bin/bash
+
+grepCmd=$(which grep)
+cronLog='/var/log/syslog'
+numberOfLines='50'
+
+# Month, Day, Time, Hostname, tag, user,
+
+result=$($grepCmd -m$numberOfLines CRON $cronLog \
+	| awk '{ s = ""; for (i = 6; i <= NF; i++) s = s $i " "; \
+			print "{\"time\" : \"" $1" "$2" "$3 "\"," \
+					"\"user\" : \"" $6 "\"," \
+					"\"message\" : \"" $5" "s "\"" \
+				"},"
+			}'
+	)
+
+echo [${result%?}]

+ 14 - 0
libs/modules/shell_files/current_ram.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+awkCmd=`which awk`
+catCmd=`which cat`
+grepCmd=`which grep`
+memInfoFile="/proc/meminfo"
+
+# References:
+#   Calculations: http://zcentric.com/2012/05/29/mapping-procmeminfo-to-output-of-free-command/
+#   Fields: https://www.kernel.org/doc/Documentation/filesystems/proc.txt
+
+memInfo=`$catCmd $memInfoFile | $grepCmd 'MemTotal\|MemFree\|Buffers\|Cached'`
+
+echo $memInfo | $awkCmd '{print "{ \"total\": " ($2/1024) ", \"used\": " ( ($2-($5+$8+$11))/1024 ) ", \"free\": " (($5+$8+$11)/1024) " }"  }'

+ 4 - 0
libs/modules/shell_files/disk_partitions.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+result=$(/bin/df -Ph | awk 'NR>1 {print "{\"file_system\": \"" $1 "\", \"size\": \"" $2 "\", \"used\": \"" $3 "\", \"avail\": \"" $4 "\", \"used%\": \"" $5 "\", \"mounted\": \"" $6 "\"},"}')
+
+echo [ ${result%?} ]

+ 40 - 0
libs/modules/shell_files/download_transfer_rate.sh

@@ -0,0 +1,40 @@
+#!/bin/bash
+
+files=(/sys/class/net/*)
+pos=$(( ${#files[*]} - 1 ))
+last=${files[$pos]}
+
+json_output="{"
+
+for interface in "${files[@]}" 
+do
+	basename=$(basename "$interface")
+	
+	# find the number of bytes transfered for this interface
+	in1=$(cat /sys/class/net/"$basename"/statistics/rx_bytes)
+
+	# wait a second
+	sleep 1
+
+	# check same interface again
+	in2=$(cat /sys/class/net/"$basename"/statistics/rx_bytes)
+
+	# get the difference (transfer rate)
+	in_bytes=$((in2 - in1))
+
+	# convert transfer rate to KB
+	in_kbytes=$((in_bytes / 1024))
+
+	# convert transfer rate to KB
+	json_output="$json_output \"$basename\": $in_kbytes"
+
+	# if it is not the last line
+	if [[ ! $interface == $last ]]
+	then
+		# add a comma to the line (JSON formatting)
+		json_output="$json_output,"
+	fi 
+done
+
+# close the JSON object & print to screen
+echo "$json_output}"

+ 28 - 0
libs/modules/shell_files/general_info.sh

@@ -0,0 +1,28 @@
+#!/bin/bash
+
+function displaytime {
+  local T=$1
+  local D=$((T/60/60/24))
+  local H=$((T/60/60%24))
+  local M=$((T/60%60))
+  local S=$((T%60))
+  [[ $D > 0 ]] && printf '%d days ' $D
+  [[ $H > 0 ]] && printf '%d hours ' $H
+  [[ $M > 0 ]] && printf '%d minutes ' $M
+  [[ $D > 0 || $H > 0 || $M > 0 ]] && printf 'and '
+  printf '%d seconds\n' $S
+}
+
+lsbRelease=$(/usr/bin/lsb_release -ds | sed -e 's/^"//'  -e 's/"$//')
+uname=$(/bin/uname -r | sed -e 's/^"//'  -e 's/"$//')
+os=`echo $lsbRelease $uname`
+hostname=$(/bin/hostname)
+uptime_seconds=$(/bin/cat /proc/uptime | awk '{print $1}')
+server_time=$(date)
+
+echo { \
+    \"OS\": \"$os\", \
+    \"Hostname\": \"$hostname\", \
+    \"Uptime\": \" $(displaytime ${uptime_seconds%.*}) \", \
+    \"Server Time\": \"$server_time\" \
+  }

+ 9 - 0
libs/modules/shell_files/internet_speed.sh

@@ -0,0 +1,9 @@
+#!/bin/bash
+
+SCRIPTPATH=`dirname $(readlink -f $0)`
+SPEED_TEST_SCRIPT=$SCRIPTPATH"/../python_files/speedtest_cli.py"
+
+$SPEED_TEST_SCRIPT \
+| grep 'Upload\|Download' \
+| awk 'BEGIN {print "{"} {print "\"" $1 "\": \"" $2 " " $3 "\"," } END {print "}"}' \
+| /bin/sed 'N;$s/",/"/;P;D'

+ 7 - 0
libs/modules/shell_files/io_stats.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+result=$(/bin/cat /proc/diskstats | /usr/bin/awk \
+				'{ if($4==0 && $8==0 && $12==0 && $13==0) next } \
+				{print "{ \"device\": \"" $3 "\", \"reads\": \""$4"\", \"writes\": \"" $8 "\", \"in_progress\": \"" $12 "\", \"time_in_io\": \"" $13 "\"},"}'
+		)
+
+echo [ ${result%?} ]

+ 15 - 0
libs/modules/shell_files/ip_addresses.sh

@@ -0,0 +1,15 @@
+#!/bin/bash
+awkCmd=`which awk`
+grepCmd=`which grep`
+sedCmd=`which sed`
+ifconfigCmd=`which ifconfig`
+trCmd=`which tr`
+digCmd=`which dig`
+
+externalIp=`$digCmd +short myip.opendns.com @resolver1.opendns.com`
+
+$ifconfigCmd \
+| $grepCmd -B1 "inet addr" \
+| $awkCmd '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' \
+| $awkCmd -v exIp="$externalIp" -F: 'BEGIN {print "["} { print "{ \"interface\": \"" $1 "\", \"ip\": \"" $3 "\" },"} END {print "{ \"interface\": \"external\", \"ip\": \""exIp"\" } ]"}' \
+| $trCmd -d '\r\n' 

+ 10 - 0
libs/modules/shell_files/load_avg.sh

@@ -0,0 +1,10 @@
+#!/bin/bash
+numberOfCores=$(/bin/grep -c 'model name' /proc/cpuinfo)
+
+if [ $numberOfCores -eq 0 ]; then
+	numberOfCores=1
+fi
+
+result=$(/bin/cat /proc/loadavg | /usr/bin/awk '{print "{ \"1_min_avg\": " ($1*100)/'$numberOfCores' ", \"5_min_avg\": " ($2*100)/'$numberOfCores' ", \"15_min_avg\": " ($3*100)/'$numberOfCores' "}," }')
+
+echo ${result%?}

+ 4 - 0
libs/modules/shell_files/logged_in_users.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+result=$(COLUMNS=300 /usr/bin/w -h | /usr/bin/awk '{print "{\"user\": \"" $1 "\", \"from\": \"" $3 "\", \"when\": \"" $4 "\"},"}')
+
+echo [ ${result%?} ]

+ 7 - 0
libs/modules/shell_files/memcached.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+echo "stats" \
+	| /bin/nc -w 1 127.0.0.1 11211 \
+	| /bin/grep 'bytes' \
+	| /usr/bin/awk 'BEGIN {print "{"} {print "\"" $2 "\": " $3 } END {print "}"}' \
+	| /usr/bin/tr '\r' ',' \
+	| /bin/sed 'N;$s/,\n/\n/;P;D'

+ 4 - 0
libs/modules/shell_files/memory_info.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+/bin/cat /proc/meminfo \
+	| /usr/bin/awk -F: 'BEGIN {print "{"} {print "\"" $1 "\": \"" $2 "\"," } END {print "}"}' \
+	| /bin/sed 'N;$s/,\n/\n/;P;D'

+ 13 - 0
libs/modules/shell_files/network_connections.sh

@@ -0,0 +1,13 @@
+#!/bin/bash
+netstatCmd=`which netstat`
+awkCmd=`which awk`
+sortCmd=`which sort`
+uniqCmd=`which uniq`
+sedCmd=`which sed`
+
+$netstatCmd -ntu \
+| $awkCmd 'NR>2 {print $5}' \
+| $sortCmd \
+| $uniqCmd -c \
+| $awkCmd 'BEGIN {print "["} {print "{ \"connections\": " $1 ", \"address\": \"" $2 "\" }," } END {print "]"}' \
+| $sedCmd 'N;$s/},/}/;P;D'

+ 7 - 0
libs/modules/shell_files/number_of_cpu_cores.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+
+numberOfCores=$(/bin/grep -c 'model name' /proc/cpuinfo)
+
+if [length($numberOfCores)]; then
+	echo "cannnot be found";
+fi

+ 28 - 0
libs/modules/shell_files/ping.sh

@@ -0,0 +1,28 @@
+#!/bin/bash
+# http://askubuntu.com/questions/413367/ping-multiple-ips-using-bash
+
+# get absolute path to config file
+SCRIPTPATH=`dirname $(readlink -f $0)`
+CONFIG_PATH=$SCRIPTPATH"/../config/ping_hosts"
+
+catCmd=`which cat`
+pingCmd=`which ping`
+awkCmd=`which awk`
+sedCmd=`which sed`
+numOfLinesInConfig=`$sedCmd -n '$=' $CONFIG_PATH`
+result='['
+
+{ $catCmd $CONFIG_PATH; echo; } \
+|  while read output
+	do
+	   	singlePing=$($pingCmd -qc 2 $output \
+	    | $awkCmd -F/ 'BEGIN { endLine="}," } /^rtt/ { if ('$numOfLinesInConfig'==1){endLine="}"} print "{" "\"host\": \"'$output'\", \"ping\": " $5 " " endLine }' \
+	    )
+	    numOfLinesInConfig=$(($numOfLinesInConfig-1))
+	    result=$result$singlePing
+		if [ $numOfLinesInConfig -eq 1 ]
+			then
+				echo $result"]"
+		fi
+	done \
+| $sedCmd 's/\},]/}]/g'

+ 12 - 0
libs/modules/shell_files/ram_intensive_processes.sh

@@ -0,0 +1,12 @@
+#!/bin/bash
+result=$(/bin/ps axo pid,user,pmem,rss,vsz,comm --sort -pmem,-rss,-vsz \
+			| head -n 15 \
+			| /usr/bin/awk 'NR>1 {print "{ \"pid\": " $1 \
+										", \"user\": \"" $2 \
+										"\", \"mem%\": " $3 \
+										", \"rss\": " $4 \
+										", \"vsz\": " $5 \
+										", \"cmd\": \"" $6 \
+										"\"},"}')
+
+echo [ ${result%?} ]

+ 10 - 0
libs/modules/shell_files/recent_account_logins.sh

@@ -0,0 +1,10 @@
+#!/bin/bash
+result=$(/usr/bin/lastlog -t 365 \
+			| /usr/bin/awk 'NR>1 {\
+				print "{ \
+					\"user\": \"" $1 "\", \
+					\"ip\": \"" $3 "\","" \
+					\"date\": \"" $5" "$6" "$7" "$8" "$9 "\"},"
+				}'
+		)
+echo [ ${result%?} ]

+ 18 - 0
libs/modules/shell_files/redis.sh

@@ -0,0 +1,18 @@
+#!/bin/bash
+
+########### Enter Your Redis Password  HERE #########
+redisPassword=''
+########### Enter Your Redis Password  HERE #########
+
+redisCommand=$(which redis-cli);
+
+if [ -n "$redisPassword" ]; then
+	redisCommand="$redisCommand -a $redisPassword"    
+fi
+
+result=$($redisCommand INFO \
+			| grep 'redis_version\|connected_clients\|connected_slaves\|used_memory_human\|total_connections_received\|total_commands_processed' \
+			| awk -F: '{print "\"" $1 "\":" "\"" $2 }' \
+			| tr '\r' '"' | tr '\n' ','
+		)
+echo { ${result%?} }

+ 88 - 0
libs/modules/shell_files/scheduled_crons.sh

@@ -0,0 +1,88 @@
+#!/bin/bash
+######
+# Credit: http://stackoverflow.com/questions/134906/how-do-i-list-all-cron-jobs-for-all-users#answer-137173
+######
+
+catCmd=`which cat`
+awkCmd=`which awk`
+sedCmd=`which sed`
+egrepCmd=`which egrep`
+echoCmd=`which echo`
+crontabCmd=`which crontab`
+
+# System-wide crontab file and cron job directory. Change these for your system.
+CRONTAB='/etc/crontab'
+CRONDIR='/etc/cron.d'
+
+# Single tab character. Annoyingly necessary.
+tab=$(echo -en "\t")
+
+# Given a stream of crontab lines, exclude non-cron job lines, replace
+# whitespace characters with a single space, and remove any spaces from the
+# beginning of each line.
+function clean_cron_lines() {
+    while read line ; do
+        $echoCmd "${line}" |
+            $egrepCmd --invert-match '^($|\s*#|\s*[[:alnum:]_]+=)' |
+            $sedCmd --regexp-extended "s/\s+/ /g" |
+            $sedCmd --regexp-extended "s/^ //"
+    done;
+}
+
+# Given a stream of cleaned crontab lines, $echoCmd any that don't include the
+# run-parts command, and for those that do, show each job file in the run-parts
+# directory as if it were scheduled explicitly.
+function lookup_run_parts() {
+    while read line ; do
+        match=$($echoCmd "${line}" | $egrepCmd -o 'run-parts (-{1,2}\S+ )*\S+')
+
+        if [[ -z "${match}" ]] ; then
+            $echoCmd "${line}"
+        else
+            cron_fields=$($echoCmd "${line}" | cut -f1-6 -d' ')
+            cron_job_dir=$($echoCmd  "${match}" | awk '{print $NF}')
+
+            if [[ -d "${cron_job_dir}" ]] ; then
+                for cron_job_file in "${cron_job_dir}"/* ; do  # */ <not a comment>
+                    [[ -f "${cron_job_file}" ]] && $echoCmd "${cron_fields} ${cron_job_file}"
+                done
+            fi
+        fi
+    done;
+}
+
+# Temporary file for crontab lines.
+temp=$(mktemp) || exit 1
+
+# Add all of the jobs from the system-wide crontab file.
+$catCmd "${CRONTAB}" | clean_cron_lines | lookup_run_parts >"${temp}" 
+
+# Add all of the jobs from the system-wide cron directory.
+$catCmd "${CRONDIR}"/* | clean_cron_lines >>"${temp}"  # */ <not a comment>
+
+# Add each user's crontab (if it exists). Insert the user's name between the
+# five time fields and the command.
+while read user ; do
+    $crontabCmd -l -u "${user}" 2>/dev/null |
+        clean_cron_lines |
+        $sedCmd --regexp-extended "s/^((\S+ +){5})(.+)$/\1${user} \3/" >>"${temp}"
+done < <(cut --fields=1 --delimiter=: /etc/passwd)
+
+# Output the collected crontab lines.
+
+## Changes: Parses output into JSON
+
+$catCmd "${temp}" \
+    | awk 'BEGIN {print "["} \
+                {print "{ \"min(s)\": \"" $1 \
+                "\", \"hours(s)\": \"" $2 "\", " \
+                " \"day(s)\": \"" $3 "\", " \
+                " \"month\": \"" $4 "\", " \
+                " \"weekday\": \"" $5 "\", " \
+                " \"user\": \"" $6 "\", " \
+                " \"command\": \"" $7$8$9$10 "\" " \
+                "}," } \
+            END {print "]"}' \
+    | $sedCmd 'N;$s/,\n/\n/;P;D'
+
+rm --force "${temp}"

+ 5 - 0
libs/modules/shell_files/swap.sh

@@ -0,0 +1,5 @@
+#!/bin/bash
+result=$(/bin/cat /proc/swaps \
+			| /usr/bin/awk 'NR>1 {print "{ \"filename\": \"" $1"\", \"type\": \""$2"\", \"size\": \""$3"\", \"used\": \""$4"\", \"priority\": \""$5"\"}," }'
+		)
+echo [ ${result%?} ]

+ 40 - 0
libs/modules/shell_files/upload_transfer_rate.sh

@@ -0,0 +1,40 @@
+#!/bin/bash
+
+files=(/sys/class/net/*)
+pos=$(( ${#files[*]} - 1 ))
+last=${files[$pos]}
+
+json_output="{"
+
+for interface in "${files[@]}" 
+do
+	basename=$(basename "$interface")
+	
+	# find the number of bytes transfered for this interface
+	out1=$(cat /sys/class/net/"$basename"/statistics/tx_bytes)
+
+	# wait a second
+	sleep 1
+
+	# check same interface again
+	out2=$(cat /sys/class/net/"$basename"/statistics/tx_bytes)	
+
+	# get the difference (transfer rate)
+	out_bytes=$((out2 - out1))
+
+	# convert transfer rate to KB
+	out_kbytes=$((out_bytes / 1024))
+
+	# convert transfer rate to KB
+	json_output="$json_output \"$basename\": $out_kbytes"
+
+	# if it is not the last line
+	if [[ ! $interface == $last ]]
+	then
+		# add a comma to the line (JSON formatting)
+		json_output="$json_output,"
+	fi 
+done
+
+# close the JSON object & print to screen
+echo "$json_output}"

+ 14 - 0
libs/modules/shell_files/user_accounts.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+result=$(/usr/bin/awk -F: '{ \
+				if ($3<=499){userType="system";} \
+				else {userType="user";} \
+				print "{ \"type\": \"" userType "\"" ", \"user\": \"" $1 "\", \"home\": \"" $6 "\" }," }' < /etc/passwd
+		)
+
+length=$(echo ${#result}) 
+
+if [ $length -eq 0 ]; then
+	result=$(getent passwd | /usr/bin/awk -F: '{ if ($3<=499){userType="system";} else {userType="user";} print "{ \"type\": \"" userType "\"" ", \"user\": \"" $1 "\", \"home\": \"" $6 "\" }," }')
+fi
+
+echo [ ${result%?} ]

+ 1 - 0
libs/timedtask/kpi.go

@@ -0,0 +1 @@
+package timedtask

+ 16 - 0
libs/timedtask/license.go

@@ -0,0 +1,16 @@
+package timedtask
+
+import (
+	"time"
+
+	"53it.net/agent/libs/common"
+)
+
+// 许可证文件定时验证
+func LicenseTimedtask() {
+	for {
+		common.CheckLicense()
+		// 5分钟检查一次许可证文件
+		time.Sleep(60 * 5 * time.Second)
+	}
+}

+ 1 - 0
libs/timedtask/timedtask.go

@@ -0,0 +1 @@
+package timedtask

File diff suppressed because it is too large
+ 9875 - 0
logs/error.log


+ 87 - 0
main.go

@@ -0,0 +1,87 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"runtime"
+	"time"
+
+	"github.com/kardianos/service"
+
+	"53it.net/agent/http"
+	"53it.net/agent/libs/common"
+	"53it.net/agent/libs/config"
+	"53it.net/agent/libs/timedtask"
+)
+
+var logger service.Logger
+
+type program struct{}
+
+func (p *program) Start(s service.Service) error {
+	// 开启异步任务,开启服务
+	go p.run()
+	return nil
+}
+func (p *program) run() {
+	// 具体工作内容
+	runtime.GOMAXPROCS(runtime.NumCPU())
+	// 写根目录到文件
+	common.WriteRootDir()
+	// 启动对应服务
+	services()
+}
+func (p *program) Stop(s service.Service) error {
+	// 停止任务,3秒后返回
+	<-time.After(time.Second * 3)
+	return nil
+}
+
+func main() {
+	svcConfig := &service.Config{
+		Name:        "htrd-agent",
+		DisplayName: "htrd-agent",
+		Description: "Host monitoring, monitoring of the host's basic information to the administrator a clear view of the view.",
+	}
+
+	prg := &program{}
+	s, err := service.New(prg, svcConfig)
+	if err != nil {
+		log.Fatal(err)
+	}
+	if len(os.Args) > 1 {
+		err = service.Control(s, os.Args[1])
+		if err != nil {
+			log.Fatal(err)
+		}
+		return
+	}
+
+	logger, err = s.Logger(nil)
+	if err != nil {
+		log.Fatal(err)
+	}
+	err = s.Run()
+	if err != nil {
+		logger.Error(err)
+	}
+}
+
+// 实际任务
+func services() {
+	// 验证许可证文件
+	go timedtask.LicenseTimedtask()
+	// web本机展示页面
+	if config.CFG.Http.Enabled == "1" {
+		go http.StartHttp()
+		// Websocket 图折线动态
+		if config.CFG.Websocket.Enabled == "1" {
+			go http.StartWebsocket()
+		} else {
+			fmt.Println("未启用websocket服务")
+		}
+	} else {
+		fmt.Println("未启用本地查看服务")
+	}
+}

+ 45 - 0
public/20160321

@@ -0,0 +1,45 @@
+package main
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"runtime"
+	"strconv"
+
+	"53it.net/agent/http"
+	"53it.net/agent/libs/common"
+	"53it.net/agent/libs/config"
+	"53it.net/agent/libs/timedtask"
+)
+
+func main() {
+	// 全部CPU核心使用
+	runtime.GOMAXPROCS(runtime.NumCPU())
+	// 写根目录到文件
+	common.WriteRootDir()
+	// 写pid到文件
+	ioutil.WriteFile(common.GetRootDir()+"/var/agent.pid", []byte(strconv.Itoa(os.Getpid())), 0666) // 写pid
+	// 实际任务
+	services()
+	// 防止程序结束
+	select {}
+}
+
+// 实际任务
+func services() {
+	// 验证许可证文件
+	go timedtask.LicenseTimedtask()
+	// web本机展示页面
+	if config.CFG.Http.Enabled == "1" {
+		go http.StartHttp()
+		// Websocket 图折线动态
+		if config.CFG.Websocket.Enabled == "1" {
+			go http.StartWebsocket()
+		} else {
+			fmt.Println("未启用websocket服务")
+		}
+	} else {
+		fmt.Println("未启用本地查看服务")
+	}
+}

+ 232 - 0
public/application.html

@@ -0,0 +1,232 @@
+<!DOCTYPE html>
+<!--[if IE 8]> <html lang="zh-cmn-Hans" class="ie8 no-js"> <![endif]-->
+<!--[if IE 9]> <html lang="zh-cmn-Hans" class="ie9 no-js"> <![endif]-->
+<!--[if !IE]><!-->
+<html lang="zh-cmn-Hans">
+<!--<![endif]-->
+<!-- BEGIN HEAD zh-cmn-Hans -->
+<head>
+    <meta charset="utf-8"/>
+    <title>服务器监控网络仪表盘-用户自定义进程监控</title>
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+    <meta content="" name="description"/>
+    <meta content="" name="author"/>
+	<meta http-equiv="pragma" content="no-cache">
+    <!-- BEGIN GLOBAL MANDATORY STYLES -->
+    <link href="./static/plugins/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
+    <link href="./static/plugins/simple-line-icons/simple-line-icons.min.css" rel="stylesheet" type="text/css">
+    <link href="./static/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css">
+    <link href="./static/plugins/uniform/css/uniform.default.css" rel="stylesheet" type="text/css">
+    <!-- END GLOBAL MANDATORY STYLES -->
+	
+	<!-- BEGIN PAGE LEVEL STYLES -->
+	<link rel="stylesheet" type="text/css" href="./static/plugins/select2/select2.css"/>
+	<link rel="stylesheet" type="text/css" href="./static/plugins/datatables/plugins/bootstrap/dataTables.bootstrap.css"/>
+	<!-- END PAGE LEVEL STYLES -->
+	
+    <!-- BEGIN THEME STYLES -->
+    <link href="./static/css/components-rounded.css" id="style_components" rel="stylesheet" type="text/css">
+    <link href="./static/css/plugins.css" rel="stylesheet" type="text/css">
+    <link href="./static/css/layout.css" rel="stylesheet" type="text/css">
+    <link href="./static/themes/default.css" rel="stylesheet" type="text/css" id="style_color">
+    <link href="./static/css/custom.css" rel="stylesheet" type="text/css">
+	
+    <!-- END THEME STYLES -->
+    <link rel="shortcut icon" href="favicon.ico"/>
+
+</head>
+<!-- END HEAD -->
+
+<body>
+<!-- BEGIN HEADER -->
+<div class="page-header">
+
+    <!-- BEGIN HEADER TOP -->
+    <div class="page-header-top">
+        <div class="container-fluid">
+            <!-- BEGIN LOGO -->
+            <div class="page-logo">
+                <a href="index.html"><img src="./static/img/logo.jpg" alt="logo" class="logo-default"></a>
+            </div>
+            <!-- END LOGO -->
+            <!-- BEGIN RESPONSIVE MENU TOGGLER -->
+            <a href="javascript:;" class="menu-toggler"></a>
+        </div>
+    </div>
+    <!-- END HEADER TOP -->
+
+    <!-- BEGIN HEADER MENU -->
+    <div class="page-header-menu">
+        <div class="container-fluid">
+            <!-- BEGIN MEGA MENU -->
+            <div class="hor-menu ">
+                <ul class="nav navbar-nav">
+                    <li>
+                        <a href="index.html">系统状态</a>
+                    </li>
+                    <li>
+                        <a href="basic-info.html">基本信息</a>
+                    </li>
+                    <li>
+                        <a href="network.html">网络</a>
+                    </li>
+                    <li class="active">
+                        <a href="application.html">应用</a>
+                    </li>
+                </ul>
+            </div>
+            <!-- END MEGA MENU -->
+        </div>
+    </div>
+    <!-- END HEADER MENU -->
+</div>
+<!-- END HEADER -->
+
+<!-- BEGIN PAGE CONTAINER -->
+<div class="page-container">
+    <!-- BEGIN PAGE CONTENT -->
+    <div class="page-content">
+        <div class="container-fluid">
+            <!-- BEGIN PAGE CONTENT INNER -->
+            <div class="row">
+                <div class="col-md-12">
+				
+				<div class="col-md-12 col-sm-12">
+					<!-- BEGIN EXAMPLE TABLE PORTLET-->
+					<div class="portlet light">
+						<div class="portlet-title">
+							<div class="caption">
+								<i class="fa fa-cogs font-green-sharp"></i>
+								<span class="caption-subject font-green-sharp bold uppercase">自定义进程存活检查</span>
+							</div>
+							<div class="tools">
+                               <a href="javascript:;" class="collapse" data-original-title="" title=""></a>
+                           </div>
+						</div>
+						<div class="portlet-body">
+							<table class="table table-striped table-bordered table-hover" id="sample_4">
+							<thead>
+							<tr>
+								<th>name</th>
+								<th>LOCATION</th>
+								<th>RUN</th>
+								<th>COUNT</th>
+							</tr>
+							</thead>
+							<tbody>
+
+							</tbody>
+							</table>
+						</div>
+					</div>
+					<!-- END EXAMPLE TABLE PORTLET-->
+				</div>
+				
+
+				
+			</div>
+
+
+
+
+                </div>
+            </div>
+            <!-- END PAGE CONTENT INNER -->
+        </div>
+    </div>
+    <!-- END PAGE CONTENT -->
+</div>
+<!-- END PAGE CONTAINER -->
+
+
+
+<!-- BEGIN PRE-FOOTER -->
+<div class="page-prefooter">
+    <div class="container-fluid">
+        <div class="row">
+            <div class="col-md-6 col-sm-6 col-xs-12 footer-block">
+                <h2>关于</h2>
+                <p>
+                    主机监控,监控主机的运行基本信息给管理员一个清晰的查看视图
+                </p>
+            </div>
+
+            <div class="col-md-6 col-sm-6 col-xs-12 footer-block">
+                <h2>联系方式</h2>
+                <address class="margin-bottom-40">
+                    Phone: 13241812313<br>
+                    Email: <a href="mailto:zuoxiupeng@live.com">zuoxiupeng@live.com</a>
+                </address>
+            </div>
+        </div>
+    </div>
+</div>
+<!-- END PRE-FOOTER -->
+<!-- BEGIN FOOTER -->
+<div class="page-footer">
+    <div class="container">
+        2016 &copy; 版权所有,保留一切权利! <a href="/" title="" target="_blank"></a>
+    </div>
+</div>
+<div class="scroll-to-top">
+    <i class="icon-arrow-up"></i>
+</div>
+<!-- END FOOTER -->
+<!-- BEGIN JAVASCRIPTS(Load javascripts at bottom, this will reduce page load time) -->
+<!-- BEGIN CORE PLUGINS -->
+<!--[if lt IE 9]>
+<script src="./static/plugins/respond.min.js"></script>
+<script src="./static/plugins/excanvas.min.js"></script>
+<![endif]-->
+<script src="./static/plugins/jquery.min.js" type="text/javascript"></script>
+<script src="./static/plugins/jquery-migrate.min.js" type="text/javascript"></script>
+<!-- IMPORTANT! Load jquery-ui.min.js before bootstrap.min.js to fix bootstrap tooltip conflict with jquery ui tooltip -->
+<script src="./static/plugins/jquery-ui/jquery-ui.min.js" type="text/javascript"></script>
+<script src="./static/plugins/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
+<script src="./static/plugins/bootstrap-hover-dropdown/bootstrap-hover-dropdown.min.js" type="text/javascript"></script>
+<script src="./static/plugins/jquery-slimscroll/jquery.slimscroll.min.js" type="text/javascript"></script>
+<script src="./static/plugins/jquery.blockui.min.js" type="text/javascript"></script>
+<script src="./static/plugins/jquery.cokie.min.js" type="text/javascript"></script>
+<script src="./static/plugins/uniform/jquery.uniform.min.js" type="text/javascript"></script>
+<!-- END CORE PLUGINS -->
+
+
+<!-- BEGIN PAGE LEVEL PLUGINS -->
+<script src="./static/plugins/flot/jquery.flot.min.js"></script>
+<script src="./static/plugins/flot/jquery.flot.resize.min.js"></script>
+<script src="./static/plugins/flot/jquery.flot.pie.min.js"></script>
+<script src="./static/plugins/flot/jquery.flot.stack.min.js"></script>
+<script src="./static/plugins/flot/jquery.flot.crosshair.min.js"></script>
+<script src="./static/plugins/flot/jquery.flot.categories.min.js" type="text/javascript"></script>
+<!-- END PAGE LEVEL PLUGINS -->
+
+
+<!-- BEGIN PAGE LEVEL PLUGINS -->
+<script type="text/javascript" src="./static/plugins/select2/select2.min.js"></script>
+<script type="text/javascript" src="./static/plugins/datatables/media/js/jquery.dataTables.min.js"></script>
+<script type="text/javascript" src="./static/plugins/datatables/plugins/bootstrap/dataTables.bootstrap.js"></script>
+<!-- END PAGE LEVEL PLUGINS -->
+
+
+<script src="./static/js/config.js" type="text/javascript"></script>
+<script src="./static/js/metronic.js" type="text/javascript"></script>
+<script src="./static/js/layout.js" type="text/javascript"></script>
+<script src="./static/js/demo.js" type="text/javascript"></script>
+<script src="./static/js/table-application.js"></script>
+<script>
+    jQuery(document).ready(function() {
+        // initiate layout and plugins
+        Metronic.init(); // init metronic core components
+        Layout.init(); // init current layout
+        Demo.init(); // init demo features
+
+		TableManaged.init();
+		
+    });
+</script>
+
+</body>
+<!-- END BODY -->
+</html>

+ 350 - 0
public/basic-info.html

@@ -0,0 +1,350 @@
+<!DOCTYPE html>
+<!--[if IE 8]> <html lang="zh-cmn-Hans" class="ie8 no-js"> <![endif]-->
+<!--[if IE 9]> <html lang="zh-cmn-Hans" class="ie9 no-js"> <![endif]-->
+<!--[if !IE]><!-->
+<html lang="zh-cmn-Hans">
+<!--<![endif]-->
+<!-- BEGIN HEAD zh-cmn-Hans -->
+<head>
+    <meta charset="utf-8"/>
+    <title>服务器监控网络仪表盘-基本信息</title>
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+    <meta content="" name="description"/>
+    <meta content="" name="author"/>
+	<meta http-equiv="pragma" content="no-cache">
+    <!-- BEGIN GLOBAL MANDATORY STYLES -->
+    <link href="./static/plugins/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
+    <link href="./static/plugins/simple-line-icons/simple-line-icons.min.css" rel="stylesheet" type="text/css">
+    <link href="./static/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css">
+    <link href="./static/plugins/uniform/css/uniform.default.css" rel="stylesheet" type="text/css">
+    <!-- END GLOBAL MANDATORY STYLES -->
+	
+	<!-- BEGIN PAGE LEVEL STYLES -->
+	<link rel="stylesheet" type="text/css" href="./static/plugins/select2/select2.css"/>
+	<link rel="stylesheet" type="text/css" href="./static/plugins/datatables/plugins/bootstrap/dataTables.bootstrap.css"/>
+	<!-- END PAGE LEVEL STYLES -->
+	
+    <!-- BEGIN THEME STYLES -->
+    <link href="./static/css/components-rounded.css" id="style_components" rel="stylesheet" type="text/css">
+    <link href="./static/css/plugins.css" rel="stylesheet" type="text/css">
+    <link href="./static/css/layout.css" rel="stylesheet" type="text/css">
+    <link href="./static/themes/default.css" rel="stylesheet" type="text/css" id="style_color">
+    <link href="./static/css/custom.css" rel="stylesheet" type="text/css">
+	
+    <!-- END THEME STYLES -->
+    <link rel="shortcut icon" href="favicon.ico"/>
+
+</head>
+<!-- END HEAD -->
+
+<body>
+<!-- BEGIN HEADER -->
+<div class="page-header">
+
+    <!-- BEGIN HEADER TOP -->
+    <div class="page-header-top">
+        <div class="container-fluid">
+            <!-- BEGIN LOGO -->
+            <div class="page-logo">
+                <a href="index.html"><img src="./static/img/logo.jpg" alt="logo" class="logo-default"></a>
+            </div>
+            <!-- END LOGO -->
+            <!-- BEGIN RESPONSIVE MENU TOGGLER -->
+            <a href="javascript:;" class="menu-toggler"></a>
+        </div>
+    </div>
+    <!-- END HEADER TOP -->
+
+    <!-- BEGIN HEADER MENU -->
+    <div class="page-header-menu">
+        <div class="container-fluid">
+            <!-- BEGIN MEGA MENU -->
+            <div class="hor-menu ">
+                <ul class="nav navbar-nav">
+                    <li>
+                        <a href="index.html">系统状态</a>
+                    </li>
+                    <li class="active">
+                        <a href="basic-info.html">基本信息</a>
+                    </li>
+                    <li>
+                        <a href="network.html">网络</a>
+                    </li>
+                    <li>
+                        <a href="application.html">应用</a>
+                    </li>
+                </ul>
+            </div>
+            <!-- END MEGA MENU -->
+        </div>
+    </div>
+    <!-- END HEADER MENU -->
+</div>
+<!-- END HEADER -->
+
+<!-- BEGIN PAGE CONTAINER -->
+<div class="page-container">
+    <!-- BEGIN PAGE CONTENT -->
+    <div class="page-content">
+        <div class="container-fluid">
+            <!-- BEGIN PAGE CONTENT INNER -->
+            <div class="row">
+                <div class="col-md-12">
+
+
+
+
+			 	<div class="row">
+				<div class="col-md-4 col-sm-12">
+					<!-- BEGIN EXAMPLE TABLE PORTLET-->
+					<div class="portlet light this_height">
+						<div class="portlet-title">
+							<div class="caption">
+								<i class="fa fa-cogs font-green-sharp"></i>
+								<span class="caption-subject font-green-sharp bold uppercase">基本信息</span>
+							</div>
+							<div class="tools">
+                               <a href="javascript:;" class="collapse" data-original-title="" title=""></a>
+                           </div>
+						</div>
+						<div class="portlet-body">
+							<table class="table table-striped table-bordered table-hover" id="sample_1">
+							<thead>
+								<tr>
+									<th>名称</th>
+									<th>值</th>
+								</tr>
+							</thead>
+							<tbody>
+
+							</tbody>
+							</table>
+						</div>
+					</div>
+					<!-- END EXAMPLE TABLE PORTLET-->
+				</div>
+
+				
+				<div class="col-md-4 col-sm-12">
+					<!-- BEGIN EXAMPLE TABLE PORTLET-->
+					<div class="portlet light this_height">
+						<div class="portlet-title">
+							<div class="caption">
+								<i class="fa fa-cogs font-green-sharp"></i>
+								<span class="caption-subject font-green-sharp bold uppercase">内存信息</span>
+							</div>
+							<div class="tools">
+                               <a href="javascript:;" class="collapse" data-original-title="" title=""></a>
+                           </div>
+						</div>
+						<div class="portlet-body">
+							<table class="table table-striped table-bordered table-hover" id="sample_2">
+							<thead>
+								<tr>
+									<th>名称</th>
+									<th>值</th>
+								</tr>
+							</thead>
+							<tbody>
+
+							</tbody>
+							</table>
+						</div>
+					</div>
+					<!-- END EXAMPLE TABLE PORTLET-->
+				</div>
+				
+				
+				<div class="col-md-4 col-sm-12">
+					<!-- BEGIN EXAMPLE TABLE PORTLET-->
+					<div class="portlet light this