-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
POC: remote data collection over existing postgres connection #80
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,20 +3,83 @@ | |
from datetime import timedelta | ||
from multiprocessing import cpu_count | ||
|
||
import psycopg2 | ||
|
||
from pg_view.collectors.base_collector import StatCollector | ||
from pg_view.loggers import logger | ||
from pg_view.models.outputs import COLSTATUS, COLHEADER | ||
|
||
|
||
UPTIME_FILENAME = '/proc/uptime' | ||
|
||
class LocalHostDataSource(object): | ||
def __int__(self): | ||
pass | ||
|
||
def __call__(self): | ||
try: | ||
with open(UPTIME_FILENAME, 'rU') as f: | ||
uptime = f.read().split() | ||
except: | ||
uptime = 0 | ||
try: | ||
ncpus = cpu_count() | ||
except: | ||
logger.error('multiprocessing does not support cpu_count') | ||
ncpus = 0 | ||
return { | ||
'uptime': uptime, | ||
'loadavg': os.getloadavg(), | ||
'hostname': socket.gethostname(), | ||
'uname': os.uname(), | ||
'ncpus': ncpus | ||
} | ||
|
||
|
||
class RemoteHostDataSource(object): | ||
def __init__(self, pgcon): | ||
self.pgcon = pgcon | ||
|
||
def __call__(self): | ||
""" | ||
CREATE OR REPLACE FUNCTION pgview.get_host_info(OUT uptime double precision[], OUT loadavg double precision[], OUT hostname text, OUT uname text[], OUT ncpus integer) | ||
RETURNS record | ||
LANGUAGE plpythonu | ||
AS $function$ | ||
import os | ||
import socket | ||
from multiprocessing import cpu_count | ||
try: | ||
with open('/proc/uptime', 'rU') as f: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a nitpick, we should not use hard-coded names when generating sprocs text. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was just copy-paste from my psql prompt, so I don't lose the func definition ;-) |
||
uptime = f.read().split() | ||
except: | ||
uptime = 0 | ||
try: | ||
ncpus = cpu_count() | ||
except: | ||
ncpus = 0 | ||
return (uptime, os.getloadavg(), socket.gethostname(), os.uname(), ncpus) | ||
$function$ | ||
""" | ||
cur = self.pgcon.cursor(cursor_factory=psycopg2.extras.RealDictCursor) | ||
cur.execute("SELECT * FROM pgview.get_host_info()") | ||
res = cur.fetchone() | ||
cur.close() | ||
self.pgcon.commit() | ||
return res | ||
|
||
|
||
class HostStatCollector(StatCollector): | ||
|
||
""" General system-wide statistics """ | ||
|
||
UPTIME_FILE = '/proc/uptime' | ||
data = {} | ||
|
||
def __init__(self): | ||
def __init__(self, data_source=LocalHostDataSource()): | ||
super(HostStatCollector, self).__init__(produce_diffs=False) | ||
|
||
self.data_source = data_source | ||
|
||
self.transform_list_data = [{'out': 'loadavg', 'infn': self._concat_load_avg}] | ||
self.transform_uptime_data = [{'out': 'uptime', 'in': 0, 'fn': self._uptime_to_str}] | ||
self.transform_uname_data = [{'out': 'sysname', 'infn': self._construct_sysname}] | ||
|
@@ -65,6 +128,8 @@ def __init__(self): | |
self.postinit() | ||
|
||
def refresh(self): | ||
self.data = self.data_source() | ||
|
||
raw_result = {} | ||
raw_result.update(self._read_uptime()) | ||
raw_result.update(self._read_load_average()) | ||
|
@@ -74,7 +139,7 @@ def refresh(self): | |
self._do_refresh([raw_result]) | ||
|
||
def _read_load_average(self): | ||
return self._transform_list(os.getloadavg()) | ||
return self._transform_list(self.data['loadavg']) | ||
|
||
def _load_avg_state(self, row, col): | ||
state = {} | ||
|
@@ -111,44 +176,26 @@ def _load_avg_status(self, row, col, val, bound): | |
return True | ||
return False | ||
|
||
@staticmethod | ||
def _read_cpus(): | ||
cpus = 0 | ||
try: | ||
cpus = cpu_count() | ||
except: | ||
logger.error('multiprocessing does not support cpu_count') | ||
pass | ||
return {'cores': cpus} | ||
def _read_cpus(self): | ||
return {'cores': self.data['ncpus']} | ||
|
||
def _construct_sysname(self, attname, row, optional): | ||
if len(row) < 3: | ||
return None | ||
return '{0} {1}'.format(row[0], row[2]) | ||
|
||
def _read_uptime(self): | ||
fp = None | ||
raw_result = [] | ||
try: | ||
fp = open(HostStatCollector.UPTIME_FILE, 'rU') | ||
raw_result = fp.read().split() | ||
except: | ||
logger.error('Unable to read uptime from {0}'.format(HostStatCollector.UPTIME_FILE)) | ||
finally: | ||
fp and fp.close() | ||
return self._transform_input(raw_result, self.transform_uptime_data) | ||
return self._transform_input(self.data['uptime'], self.transform_uptime_data) | ||
|
||
@staticmethod | ||
def _uptime_to_str(uptime): | ||
return str(timedelta(seconds=int(float(uptime)))) | ||
|
||
@staticmethod | ||
def _read_hostname(): | ||
return {'hostname': socket.gethostname()} | ||
def _read_hostname(self): | ||
return {'hostname': self.data['hostname']} | ||
|
||
def _read_uname(self): | ||
uname_row = os.uname() | ||
return self._transform_input(uname_row, self.transform_uname_data) | ||
return self._transform_input(self.data['uname'], self.transform_uname_data) | ||
|
||
def output(self, method): | ||
return super(self.__class__, self).output(method, before_string='Host statistics', after_string='\n') |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,9 +91,10 @@ def process_single_collector(st): | |
|
||
def process_groups(groups): | ||
for name in groups: | ||
part = groups[name]['partitions'] | ||
pg = groups[name]['pg'] | ||
part.ncurses_set_prefix(pg.ncurses_produce_prefix()) | ||
part = groups[name].get('partitions') | ||
if part: | ||
pg = groups[name]['pg'] | ||
part.ncurses_set_prefix(pg.ncurses_produce_prefix()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will not show useful information about the cluster (i.e. version, max connections, active and idle ones). I think we need to do pg.ncurses_set_prefix(pg.ncurses_produce_prefix()), attaching it to the header of pg collector. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a temp hack to avoid it crashing because partition collector doesn't have a remote data source yet. |
||
|
||
|
||
def dbversion_as_float(pgcon): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
host name can be also read from the configuration file