83 lines
3.2 KiB
Python
83 lines
3.2 KiB
Python
import collectd,os,subprocess,sys,re,time
|
|
|
|
# https://www.programcreek.com/python/example/106897/collectd.register_read
|
|
|
|
PATHS = [] # { name, dir, exclude }
|
|
# there is a pattern in carbon/storage-schemas.conf which stores values every 12h for a year
|
|
INTERVAL = 60 * 60 * 12 # twice a day. change values in docker-graphite if you change this
|
|
|
|
def du(pathinfo):
|
|
# -B1 makes du print block sizes and not apparent sizes (to match df which also uses block sizes)
|
|
cmd = 'timeout 1800 du -DsB1 "{}"'.format(pathinfo['dir'])
|
|
if pathinfo['exclude'] != '':
|
|
cmd += ' --exclude "{}"'.format(pathinfo['exclude'])
|
|
|
|
collectd.info('computing size with command: %s' % cmd);
|
|
try:
|
|
size = subprocess.check_output(cmd, shell=True).split()[0].decode('utf-8')
|
|
collectd.info('\tsize of %s is %s (time: %i)' % (pathinfo['dir'], size, int(time.time())))
|
|
return size
|
|
except Exception as e:
|
|
collectd.info('\terror getting the size of %s: %s' % (pathinfo['dir'], str(e)))
|
|
return 0
|
|
|
|
def parseSize(size):
|
|
units = {"B": 1, "KB": 10**3, "MB": 10**6, "GB": 10**9, "TB": 10**12}
|
|
number, unit, _ = re.split('([a-zA-Z]+)', size.upper())
|
|
return int(float(number)*units[unit])
|
|
|
|
def dockerSize():
|
|
# use --format '{{json .}}' to dump the string. '{{if eq .Type "Images"}}{{.Size}}{{end}}' still creates newlines
|
|
# https://godoc.org/github.com/docker/go-units#HumanSize is used. so it's 1000 (KB) and not 1024 (KiB)
|
|
cmd = 'timeout 1800 docker system df --format "{{.Size}}" | head -n1'
|
|
try:
|
|
size = subprocess.check_output(cmd, shell=True).strip().decode('utf-8')
|
|
collectd.info('size of docker images is %s (%s) (time: %i)' % (size, parseSize(size), int(time.time())))
|
|
return parseSize(size)
|
|
except Exception as e:
|
|
collectd.info('error getting docker images size : %s' % str(e))
|
|
return 0
|
|
|
|
# configure is called for each module block. this is called before init
|
|
def configure(config):
|
|
global PATHS
|
|
|
|
for child in config.children:
|
|
if child.key != 'Path':
|
|
collectd.info('du plugin: Unknown config key "%s"' % key)
|
|
continue
|
|
|
|
pathinfo = { 'name': '', 'dir': '', 'exclude': '' }
|
|
for node in child.children:
|
|
if node.key == 'Instance':
|
|
pathinfo['name'] = node.values[0]
|
|
elif node.key == 'Dir':
|
|
pathinfo['dir'] = node.values[0]
|
|
elif node.key == 'Exclude':
|
|
pathinfo['exclude'] = node.values[0]
|
|
|
|
PATHS.append(pathinfo);
|
|
collectd.info('du plugin: monitoring %s' % pathinfo['dir']);
|
|
|
|
def init():
|
|
global PATHS
|
|
collectd.info('custom du plugin initialized with %s %s' % (PATHS, sys.version))
|
|
|
|
def read():
|
|
for pathinfo in PATHS:
|
|
size = du(pathinfo)
|
|
|
|
# type comes from https://github.com/collectd/collectd/blob/master/src/types.db
|
|
val = collectd.Values(type='capacity', plugin='du', plugin_instance=pathinfo['name'])
|
|
val.dispatch(values=[size], type_instance='usage')
|
|
|
|
size = dockerSize()
|
|
val = collectd.Values(type='capacity', plugin='du', plugin_instance='docker')
|
|
val.dispatch(values=[size], type_instance='usage')
|
|
|
|
|
|
|
|
collectd.register_init(init)
|
|
collectd.register_config(configure)
|
|
collectd.register_read(read, INTERVAL)
|