22import docker
33import humanize
44import concurrent .futures
5- from flask import Flask , jsonify
5+ from flask import Flask , jsonify , send_from_directory
66from datetime import datetime , timezone
7+ import os
78
89app = Flask (__name__ )
910
1011def get_host_resources ():
12+ # Uptime
13+ boot_time = psutil .boot_time ()
14+ uptime_seconds = int (datetime .now (timezone .utc ).timestamp () - boot_time )
15+ # Load average
16+ load1 , load5 , load15 = psutil .getloadavg ()
17+ # CPU
18+ cpu_times = psutil .cpu_times_percent (interval = 0 )
19+ cpu_count = psutil .cpu_count ()
20+ cpu_percent = psutil .cpu_percent (interval = 0 )
21+ # Memory
1122 mem = psutil .virtual_memory ()
23+ swap = psutil .swap_memory ()
24+ # Disk
1225 disk = psutil .disk_usage ('/' )
13- cpu_percent = psutil .cpu_percent (interval = 0 ) # non-blocking, instantaneous
26+ # IO
27+ disk_io = psutil .disk_io_counters ()
28+ net_io = psutil .net_io_counters (pernic = True )
29+ # Processes
30+ procs = list (psutil .process_iter (['status' ]))
31+ running = sum (1 for p in procs if p .info ['status' ] == psutil .STATUS_RUNNING )
32+ blocked = sum (1 for p in procs if p .info ['status' ] == psutil .STATUS_DISK_SLEEP )
33+ # Interrupts (if available)
34+ interrupts = None
35+ try :
36+ with open ("/proc/stat" ) as f :
37+ for line in f :
38+ if line .startswith ("intr" ):
39+ interrupts = int (line .split ()[1 ])
40+ except Exception :
41+ interrupts = None
42+
1443 return {
15- 'cpu_percent' : cpu_percent ,
16- 'memory' : {
17- 'total' : mem .total ,
18- 'used' : mem .used ,
19- 'percent' : mem .percent ,
20- 'total_human' : humanize .naturalsize (mem .total ),
21- 'used_human' : humanize .naturalsize (mem .used )
44+ "uptime_seconds" : uptime_seconds ,
45+ "uptime_human" : humanize .precisedelta (uptime_seconds ),
46+ "boot_time" : datetime .fromtimestamp (boot_time , tz = timezone .utc ).isoformat (),
47+ "cpu" : {
48+ "percent" : cpu_percent ,
49+ "idle_percent" : cpu_times .idle ,
50+ "count" : cpu_count ,
51+ "times" : cpu_times ._asdict ()
52+ },
53+ "memory" : {
54+ "total" : mem .total ,
55+ "available" : mem .available ,
56+ "used" : mem .used ,
57+ "free" : mem .free ,
58+ "percent" : mem .percent ,
59+ "buffers" : getattr (mem , "buffers" , 0 ),
60+ "cached" : getattr (mem , "cached" , 0 ),
61+ "total_human" : humanize .naturalsize (mem .total ),
62+ "used_human" : humanize .naturalsize (mem .used ),
63+ "available_human" : humanize .naturalsize (mem .available ),
64+ "buffers_human" : humanize .naturalsize (getattr (mem , "buffers" , 0 )),
65+ "cached_human" : humanize .naturalsize (getattr (mem , "cached" , 0 )),
66+ },
67+ "swap" : {
68+ "total" : swap .total ,
69+ "used" : swap .used ,
70+ "free" : swap .free ,
71+ "percent" : swap .percent ,
72+ "sin" : swap .sin ,
73+ "sout" : swap .sout ,
74+ "total_human" : humanize .naturalsize (swap .total ),
75+ "used_human" : humanize .naturalsize (swap .used ),
76+ "free_human" : humanize .naturalsize (swap .free ),
77+ },
78+ "disk" : {
79+ "total" : disk .total ,
80+ "used" : disk .used ,
81+ "free" : disk .free ,
82+ "percent" : disk .percent ,
83+ "total_human" : humanize .naturalsize (disk .total ),
84+ "used_human" : humanize .naturalsize (disk .used ),
85+ "free_human" : humanize .naturalsize (disk .free )
2286 },
23- 'disk' : {
24- 'total' : disk .total ,
25- 'used' : disk .used ,
26- 'percent' : disk .percent ,
27- 'total_human' : humanize .naturalsize (disk .total ),
28- 'used_human' : humanize .naturalsize (disk .used )
29- }
87+ "disk_io" : {
88+ "read_bytes" : disk_io .read_bytes ,
89+ "write_bytes" : disk_io .write_bytes ,
90+ "read_count" : disk_io .read_count ,
91+ "write_count" : disk_io .write_count ,
92+ "read_time" : getattr (disk_io , 'read_time' , None ),
93+ "write_time" : getattr (disk_io , 'write_time' , None )
94+ },
95+ "net_io" : {
96+ dev : {
97+ "bytes_sent" : val .bytes_sent ,
98+ "bytes_recv" : val .bytes_recv ,
99+ "packets_sent" : val .packets_sent ,
100+ "packets_recv" : val .packets_recv ,
101+ "errin" : val .errin ,
102+ "errout" : val .errout ,
103+ "dropin" : val .dropin ,
104+ "dropout" : val .dropout
105+ }
106+ for dev , val in net_io .items ()
107+ },
108+ "loadavg" : {
109+ "1min" : load1 ,
110+ "5min" : load5 ,
111+ "15min" : load15
112+ },
113+ "processes" : {
114+ "running" : running ,
115+ "blocked_io" : blocked
116+ },
117+ "interrupts" : interrupts
30118 }
31119
32120def calculate_cpu_percent (stat ):
@@ -134,5 +222,9 @@ def status():
134222 'docker_services' : get_docker_services ()
135223 })
136224
225+ @app .route ('/dashboard.html' )
226+ def dashboard ():
227+ return send_from_directory (os .path .dirname (os .path .abspath (__file__ )), 'dashboard.html' )
228+
137229if __name__ == "__main__" :
138- app .run (host = '0.0.0.0' , port = 8080 )
230+ app .run (host = '0.0.0.0' , port = 8080 )
0 commit comments