Automatically migrated from Gitolite
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

135 lines
3.3 KiB

9 years ago
  1. import sys, os, json
  2. from datetime import datetime
  3. # We need to set both the Python module path and system environment path, to make sure that the daemon
  4. # can find both the psutil library and its compiled libraries.
  5. sys.path.insert(0, "%s/lib" % os.path.split(os.path.realpath(__file__))[0])
  6. os.environ['PATH'] = "%s/lib:%s" % (os.path.split(os.path.realpath(__file__))[0], os.environ['PATH'])
  7. import psutil
  8. import urlparse
  9. import SocketServer, SimpleHTTPServer
  10. bind_ip = ""
  11. port = 8081
  12. def generate_stats(get_processes):
  13. listed_filesystems = ["ext2", "ext3", "ext4", "reiserfs", "removable", "fixed", "simfs"]
  14. mem = psutil.virtual_memory()
  15. swap = psutil.swap_memory()
  16. disks = {}
  17. for disk in psutil.disk_partitions(True):
  18. if disk.fstype in listed_filesystems:
  19. usage = psutil.disk_usage(disk.mountpoint)
  20. disks[disk.mountpoint] = {
  21. "device": disk.device,
  22. "options": disk.opts,
  23. "filesystem": disk.fstype,
  24. "total": usage.total,
  25. "free": usage.free
  26. }
  27. return_data = {
  28. "uptime": (datetime.now() - datetime.fromtimestamp(psutil.BOOT_TIME)).total_seconds(),
  29. "memory": {
  30. "total": mem.total,
  31. "available": mem.available,
  32. "used": mem.used,
  33. "unused": mem.free
  34. },
  35. "swap": {
  36. "total": swap.total,
  37. "used": swap.used,
  38. "unused": swap.free,
  39. "in": swap.sin,
  40. "out": swap.sout
  41. },
  42. "disk": disks,
  43. "cpu": psutil.cpu_percent(percpu=True)
  44. }
  45. if get_processes:
  46. processes = []
  47. for proc in psutil.process_iter():
  48. try:
  49. cwd = proc.getcwd()
  50. except psutil.AccessDenied, e:
  51. cwd = None
  52. processes.append({
  53. "pid": proc.pid,
  54. "parent": proc.ppid,
  55. "name": proc.name,
  56. "command": proc.cmdline,
  57. "user": proc.username,
  58. "status": str(proc.status), # If we don't explicitly use str() here, json module will get confused
  59. "cwd": cwd,
  60. "cpu": proc.get_cpu_percent(interval=0.1),
  61. "rss": proc.get_memory_info()[0]
  62. })
  63. return_data['process'] = processes
  64. return return_data
  65. class StatsHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
  66. def do_GET(self):
  67. req = urlparse.urlparse(self.path)
  68. get_params = urlparse.parse_qs(req.query)
  69. path = req.path
  70. try:
  71. get_processes = (get_params['processes'][0] == "1")
  72. except:
  73. get_processes = False
  74. if path=='/':
  75. self.send_response(200)
  76. self.send_header('Content-type','text/json')
  77. self.end_headers()
  78. self.wfile.write(json.dumps(generate_stats(get_processes)))
  79. return
  80. else:
  81. self.send_response(404)
  82. self.send_header('Content-type','text/plain')
  83. self.end_headers()
  84. self.wfile.write("404 Not Found")
  85. return
  86. #### Hacky way to daemonize the whole thing
  87. # Fork away
  88. if os.fork(): exit(0)
  89. os.umask(0)
  90. os.setsid()
  91. if os.fork(): exit(0)
  92. # Write PID to file
  93. outfile = open("pylsa.pid", "w")
  94. outfile.write('%i' % os.getpid())
  95. outfile.close()
  96. # Bind the server
  97. httpd = SocketServer.ThreadingTCPServer((bind_ip, port), StatsHandler, False)
  98. httpd.allow_reuse_address = True
  99. httpd.server_bind()
  100. httpd.server_activate()
  101. # If all went well, we'll redirect streams to silence them
  102. sys.stdout.flush()
  103. sys.stderr.flush()
  104. si = file('/dev/null', 'r')
  105. so = file('/dev/null', 'a+')
  106. se = file('/dev/null', 'a+', 0)
  107. os.dup2(si.fileno(), sys.stdin.fileno())
  108. os.dup2(so.fileno(), sys.stdout.fileno())
  109. os.dup2(se.fileno(), sys.stderr.fileno())
  110. # Done!
  111. print 'Port=',port
  112. httpd.serve_forever()