Copyright 2015, Joseph Huckaby
[MIT License](https://github.com/jhuckaby/pixl-xml)
-- [PySensors](https://bitbucket.org/blackjack/pysensors)
+- [sensors](https://github.com/paroj/sensors.py)
- Copyright 2014, Marc 'BlackJack' Rintsch
- [LGPL 2.1 License](https://bitbucket.org/blackjack/pysensors)
+ Copyright 2014, Pavel Rojtberg
+ [LGPL 2.1 License](http://opensource.org/licenses/LGPL-2.1)
- [PyYAML](https://bitbucket.org/blackjack/pysensors)
python.d/memcached.conf \
python.d/mysql.conf \
python.d/nginx.conf \
+ python.d/nginx_log.conf \
python.d/phpfpm.conf \
python.d/postfix.conf \
python.d/redis.conf \
# Enable / disable the whole python.d.plugin (all its modules)
enabled: yes
+# Prevent log flood
+# Define how many log messages can be written to log file in one log_interval
+logs_per_interval: 200
+
+# Define how long is one logging interval (in seconds)
+log_interval: 3600
+
# ----------------------------------------------------------------------
# Enable / Disable python.d.plugin modules
#
# apache: yes
# apache_cache: yes
# cpufreq: yes
+# dovecot: yes
example: no
# exim: yes
# hddtemp: yes
# ipfs: yes
+# memcached: yes
# mysql: yes
# nginx: yes
+# nginx_log: yes
# phpfpm: yes
# postfix: yes
# redis: yes
# port: PORT # the port to connect to
#
-# By default this module will try to autodetect number of disks.
-# However this can be overridden by setting variable `disk_count` to
-# desired number of disks. Example for two disks:
+# By default this module will try to autodetect disks
+# (autodetection works only for disk which names start with "sd").
+# However this can be overridden by setting variable `disks` to
+# array of desired disks. Example for two disks:
#
-# disk_count: 2
+# devices:
+# - sda
+# - sdb
#
# ----------------------------------------------------------------------
--- /dev/null
+# netdata python.d.plugin configuration for nginx log
+#
+# This file is in YaML format. Generally the format is:
+#
+# name: value
+#
+# There are 2 sections:
+# - global variables
+# - one or more JOBS
+#
+# JOBS allow you to collect values from multiple sources.
+# Each source will have its own set of charts.
+#
+# JOB parameters have to be indented (using spaces only, example below).
+
+# ----------------------------------------------------------------------
+# Global Variables
+# These variables set the defaults for all JOBs, however each JOB
+# may define its own, overriding the defaults.
+
+# update_every sets the default data collection frequency.
+# If unset, the python.d.plugin default is used.
+# update_every: 1
+
+# priority controls the order of charts at the netdata dashboard.
+# Lower numbers move the charts towards the top of the page.
+# If unset, the default for python.d.plugin is used.
+# priority: 60000
+
+# retries sets the number of retries to be made in case of failures.
+# If unset, the default for python.d.plugin is used.
+# Attempts to restore the service are made once every update_every
+# and only if the module has collected values in the past.
+# retries: 5
+
+# ----------------------------------------------------------------------
+# JOBS (data collection sources)
+#
+# The default JOBS share the same *name*. JOBS with the same name
+# are mutually exclusive. Only one of them will be allowed running at
+# any time. This allows autodetection to try several alternatives and
+# pick the one that works.
+#
+# Any number of jobs is supported.
+#
+# All python.d.plugin JOBS (for all its modules) support a set of
+# predefined parameters. These are:
+#
+# job_name:
+# name: myname # the JOB's name as it will appear at the
+# # dashboard (by default is the job_name)
+# # JOBs sharing a name are mutually exclusive
+# update_every: 1 # the JOB's data collection frequency
+# priority: 60000 # the JOB's order on the dashboard
+# retries: 5 # the JOB's number of restoration attempts
+#
+# Additionally to the above, nginx_log also supports the following:
+#
+# path: 'PATH' # the path to nginx's access.log
+#
+
+# ----------------------------------------------------------------------
+# AUTO-DETECTION JOBS
+# only one of them will run (they have the same name)
+
+nginx_log:
+ name: 'local'
+ path: '/var/log/nginx/access.log'
+
+nginx_log2:
+ name: 'local'
+ path: '/var/log/nginx/nginx-access.log'
DEBUG_FLAG = conf['debug']
except (KeyError, TypeError):
pass
+ try:
+ log_counter = conf['logs_per_interval']
+ except (KeyError, TypeError):
+ log_counter = 200
+ try:
+ log_interval = conf['log_interval']
+ except (KeyError, TypeError):
+ log_interval = 3600
for k, v in conf.items():
if k in ("update_every", "debug", "enabled"):
continue
# parse passed command line arguments
modules = parse_cmdline(MODULES_DIR, *sys.argv)
msg.DEBUG_FLAG = DEBUG_FLAG
+ msg.LOG_COUNTER = log_counter
+ msg.LOG_INTERVAL = log_interval
msg.info("MODULES_DIR='" + MODULES_DIR +
"', CONFIG_DIR='" + CONFIG_DIR +
"', UPDATE_EVERY=" + str(BASE_CONFIG['update_every']) +
memcached.chart.py \
mysql.chart.py \
nginx.chart.py \
+ nginx_log.chart.py \
phpfpm.chart.py \
postfix.chart.py \
redis.chart.py \
self.port = 7634
self.order = ORDER
self.definitions = CHARTS
- self.disk_count = 1
- self.exclude = []
+ self.disks = []
- def _get_disk_count(self):
- all_disks = [f for f in os.listdir("/dev") if len(f) == 3 and f.startswith("sd")]
- for disk in self.exclude:
- try:
- all_disks.remove(disk)
- except:
- self.debug("Disk not found")
- return len(all_disks)
+ def _get_disks(self):
+ try:
+ disks = self.configuration['devices']
+ print(disks)
+ except (KeyError, TypeError) as e:
+ self.info("Autodetecting disks")
+ return ["/dev/" + f for f in os.listdir("/dev") if len(f) == 3 and f.startswith("sd")]
+
+ ret = []
+ for disk in disks:
+ if not disk.startswith('/dev/'):
+ disk = "/dev/" + disk
+ if os.path.exists(disk):
+ ret.append(disk)
+ if len(ret) == 0:
+ self.error("Provided disks cannot be found in /dev directory.")
+ return ret
def _check_raw_data(self, data):
if not data.endswith('|'):
return False
- if data.count('|') % (5 * self.disk_count) == 0:
+ if all(disk in data for disk in self.disks):
return True
return False
return None
data = {}
for i in range(len(raw) // 5):
+ if not raw[i*5+1] in self.disks:
+ continue
try:
val = int(raw[i*5+3])
except ValueError:
:return: boolean
"""
self._parse_config()
- try:
- self.exclude = list(self.configuration['exlude'])
- except (KeyError, TypeError) as e:
- self.info("No excluded disks")
- self.debug(str(e))
-
- try:
- self.disk_count = int(self.configuration['disk_count'])
- except (KeyError, TypeError) as e:
- self.info("Autodetecting number of disks")
- self.disk_count = self._get_disk_count()
- self.debug(str(e))
+ self.disks = self._get_disks()
data = self._get_data()
if data is None:
--- /dev/null
+# -*- coding: utf-8 -*-
+# Description: nginx log netdata python.d module
+# Author: Pawel Krupa (paulfantom)
+
+from base import LogService
+import re
+
+priority = 60000
+retries = 60
+# update_every = 3
+
+ORDER = ['codes']
+CHARTS = {
+ 'codes': {
+ 'options': [None, 'nginx status codes', 'requests/s', 'requests', 'nginx_log.codes', 'stacked'],
+ 'lines': [
+ ["20X", None, "incremental"],
+ ["30X", None, "incremental"],
+ ["40X", None, "incremental"],
+ ["50X", None, "incremental"]
+ ]}
+}
+
+
+class Service(LogService):
+ def __init__(self, configuration=None, name=None):
+ LogService.__init__(self, configuration=configuration, name=name)
+ if len(self.log_path) == 0:
+ self.log_path = "/var/log/nginx/access.log"
+ self.order = ORDER
+ self.definitions = CHARTS
+ pattern = r'" ([0-9]{3}) ?'
+ #pattern = r'(?:" )([0-9][0-9][0-9]) ?'
+ self.regex = re.compile(pattern)
+
+ def _get_data(self):
+ """
+ Parse new log lines
+ :return: dict
+ """
+ data = {'20X': 0,
+ '30X': 0,
+ '40X': 0,
+ '50X': 0}
+ try:
+ raw = self._get_raw_data()
+ if raw is None:
+ return None
+ elif not raw:
+ return data
+ except (ValueError, AttributeError):
+ return None
+
+ regex = self.regex
+ for line in raw:
+ code = regex.search(line)
+ beginning = code.group(1)[0]
+
+ if beginning == '2':
+ data["20X"] += 1
+ elif beginning == '3':
+ data["30X"] += 1
+ elif beginning == '4':
+ data["40X"] += 1
+ elif beginning == '5':
+ data["50X"] += 1
+
+ return data
+
self.debug("No request specified. Using: '" + str(self.request) + "'")
self.request = self.request.encode()
+ def check(self):
+ return SimpleService.check(self)
+
class LogService(SimpleService):
def __init__(self, configuration=None, name=None):
self.command = str(self.configuration['command'])
except (KeyError, TypeError):
self.error("No command specified. Using: '" + self.command + "'")
- self.command = self.command.split(' ')
+ command = self.command.split(' ')
- for arg in self.command[1:]:
+ for arg in command[1:]:
if any(st in arg for st in self.bad_substrings):
self.error("Bad command argument:" + " ".join(self.command[1:]))
return False
# test command and search for it in /usr/sbin or /sbin when failed
- base = self.command[0].split('/')[-1]
+ base = command[0].split('/')[-1]
if self._get_raw_data() is None:
for prefix in ['/sbin/', '/usr/sbin/']:
- self.command[0] = prefix + base
- if os.path.isfile(self.command[0]):
+ command[0] = prefix + base
+ if os.path.isfile(command[0]):
break
-
+ self.command = command
if self._get_data() is None or len(self._get_data()) == 0:
self.error("Command", self.command, "returned no data")
return False
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-import os
-
-from ctypes import CDLL, c_char_p, c_int, c_void_p, c_uint, c_double, byref, Structure, get_errno,\
- POINTER, c_short, c_size_t, create_string_buffer
-from ctypes.util import find_library
-
-version_info = (0, 0, 3)
-
-__version__ = '.'.join(map(str, version_info))
-__date__ = '2014-08-17'
-__author__ = "Marc 'BlackJack' Rintsch"
-__contact__ = 'marc@rintsch.de'
-__license__ = 'LGPL v2.1'
-
-API_VERSION = 4
-DEFAULT_CONFIG_FILENAME = '/etc/sensors3.conf'
-
-LIB_FILENAME = os.environ.get('SENSORS_LIB') or find_library('sensors')
-SENSORS_LIB = CDLL(LIB_FILENAME)
-VERSION = c_char_p.in_dll(SENSORS_LIB, 'libsensors_version').value
-MAJOR_VERSION = version_info[0]
-STDC_LIB = CDLL(find_library('c'), use_errno=True)
-
-TYPE_DICT = {
- 0: 'voltage',
- 1: 'fan',
- 2: 'temperature',
- 3: 'power',
- 4: 'energy',
- 5: 'current',
- 6: 'humidity',
- 7: 'max_main',
- 16: 'vid',
- 17: 'intrusion',
- 18: 'max_other',
- 24: 'beep_enable'
-}
-
-class SensorsError(Exception):
- def __init__(self, message, error_number=None):
- Exception.__init__(self, message)
- self.error_number = error_number
-
-
-def _error_check(result, _func, _arguments):
- if result < 0:
- raise SensorsError(_strerror(result), result)
- return result
-
-_strerror = SENSORS_LIB.sensors_strerror
-_strerror.argtypes = [c_int]
-_strerror.restype = c_char_p
-
-_init = SENSORS_LIB.sensors_init
-_init.argtypes = [c_void_p]
-_init.restype = c_int
-_init.errcheck = _error_check
-
-cleanup = SENSORS_LIB.sensors_cleanup
-cleanup.argtypes = None
-cleanup.restype = None
-
-
-def init(config_filename=DEFAULT_CONFIG_FILENAME):
- file_p = STDC_LIB.fopen(config_filename.encode('utf-8'), b'r')
- if file_p is None:
- error_number = get_errno()
- raise OSError(error_number, os.strerror(error_number), config_filename)
- try:
- _init(file_p)
- finally:
- STDC_LIB.fclose(file_p)
-
-
-class Subfeature(Structure):
- _fields_ = [
- ('name', c_char_p),
- ('number', c_int),
- ('type', c_int),
- ('mapping', c_int),
- ('flags', c_uint),
- ]
-
- def __repr__(self):
- return '<%s name=%r number=%d type=%d mapping=%d flags=%08x>' % (
- self.__class__.__name__,
- self.name,
- self.number,
- self.type,
- self.mapping,
- self.flags
- )
-
- def get_value(self):
- result = c_double()
- _get_value(byref(self.parent.chip), self.number, byref(result))
- return result.value
-
-SUBFEATURE_P = POINTER(Subfeature)
-
-
-class Feature(Structure):
- _fields_ = [
- ('name', c_char_p),
- ('number', c_int),
- ('type', c_int),
- ('_first_subfeature', c_int),
- ('_padding1', c_int),
- ]
-
- def __repr__(self):
- return '<%s name=%r number=%r type=%r>' % (
- self.__class__.__name__,
- self.name,
- self.number,
- self.type
- )
+"""
+@package sensors.py
+Python Bindings for libsensors3
+
+use the documentation of libsensors for the low level API.
+see example.py for high level API usage.
+
+@author: Pavel Rojtberg (http://www.rojtberg.net)
+@see: https://github.com/paroj/sensors.py
+@copyright: LGPLv2 (same as libsensors) <http://opensource.org/licenses/LGPL-2.1>
+"""
+
+from ctypes import *
+import ctypes.util
+
+_libc = cdll.LoadLibrary(ctypes.util.find_library("c"))
+# see https://github.com/paroj/sensors.py/issues/1
+_libc.free.argtypes = [c_void_p]
+_hdl = cdll.LoadLibrary(ctypes.util.find_library("sensors"))
+
+version = c_char_p.in_dll(_hdl, "libsensors_version").value.decode("ascii")
+
+
+class bus_id(Structure):
+ _fields_ = [("type", c_short),
+ ("nr", c_short)]
+
+
+class chip_name(Structure):
+ _fields_ = [("prefix", c_char_p),
+ ("bus", bus_id),
+ ("addr", c_int),
+ ("path", c_char_p)]
+
+
+class feature(Structure):
+ _fields_ = [("name", c_char_p),
+ ("number", c_int),
+ ("type", c_int)]
+
+ # sensors_feature_type
+ IN = 0x00
+ FAN = 0x01
+ TEMP = 0x02
+ POWER = 0x03
+ ENERGY = 0x04
+ CURR = 0x05
+ HUMIDITY = 0x06
+ MAX_MAIN = 0x7
+ VID = 0x10
+ INTRUSION = 0x11
+ MAX_OTHER = 0x12
+ BEEP_ENABLE = 0x18
+
+
+class subfeature(Structure):
+ _fields_ = [("name", c_char_p),
+ ("number", c_int),
+ ("type", c_int),
+ ("mapping", c_int),
+ ("flags", c_uint)]
+
+
+_hdl.sensors_get_detected_chips.restype = POINTER(chip_name)
+_hdl.sensors_get_features.restype = POINTER(feature)
+_hdl.sensors_get_all_subfeatures.restype = POINTER(subfeature)
+_hdl.sensors_get_label.restype = c_void_p # return pointer instead of str so we can free it
+_hdl.sensors_get_adapter_name.restype = c_char_p # docs do not say whether to free this or not
+_hdl.sensors_strerror.restype = c_char_p
+
+### RAW API ###
+MODE_R = 1
+MODE_W = 2
+COMPUTE_MAPPING = 4
+
+
+def init(cfg_file=None):
+ file = _libc.fopen(cfg_file.encode("utf-8"), "r") if cfg_file is not None else None
+
+ if _hdl.sensors_init(file) != 0:
+ raise Exception("sensors_init failed")
+
+ if file is not None:
+ _libc.fclose(file)
+
+
+def cleanup():
+ _hdl.sensors_cleanup()
+
+
+def parse_chip_name(orig_name):
+ ret = chip_name()
+ err = _hdl.sensors_parse_chip_name(orig_name.encode("utf-8"), byref(ret))
+
+ if err < 0:
+ raise Exception(strerror(err))
+
+ return ret
+
+
+def strerror(errnum):
+ return _hdl.sensors_strerror(errnum).decode("utf-8")
+
+
+def free_chip_name(chip):
+ _hdl.sensors_free_chip_name(byref(chip))
+
+
+def get_detected_chips(match, nr):
+ """
+ @return: (chip, next nr to query)
+ """
+ _nr = c_int(nr)
+
+ if match is not None:
+ match = byref(match)
+
+ chip = _hdl.sensors_get_detected_chips(match, byref(_nr))
+ chip = chip.contents if bool(chip) else None
+ return chip, _nr.value
+
+
+def chip_snprintf_name(chip, buffer_size=200):
+ """
+ @param buffer_size defaults to the size used in the sensors utility
+ """
+ ret = create_string_buffer(buffer_size)
+ err = _hdl.sensors_snprintf_chip_name(ret, buffer_size, byref(chip))
+
+ if err < 0:
+ raise Exception(strerror(err))
+
+ return ret.value.decode("utf-8")
+
+
+def do_chip_sets(chip):
+ """
+ @attention this function was not tested
+ """
+ err = _hdl.sensors_do_chip_sets(byref(chip))
+ if err < 0:
+ raise Exception(strerror(err))
+
+
+def get_adapter_name(bus):
+ return _hdl.sensors_get_adapter_name(byref(bus)).decode("utf-8")
+
+
+def get_features(chip, nr):
+ """
+ @return: (feature, next nr to query)
+ """
+ _nr = c_int(nr)
+ feature = _hdl.sensors_get_features(byref(chip), byref(_nr))
+ feature = feature.contents if bool(feature) else None
+ return feature, _nr.value
+
+
+def get_label(chip, feature):
+ ptr = _hdl.sensors_get_label(byref(chip), byref(feature))
+ val = cast(ptr, c_char_p).value.decode("utf-8")
+ _libc.free(ptr)
+ return val
+
+
+def get_all_subfeatures(chip, feature, nr):
+ """
+ @return: (subfeature, next nr to query)
+ """
+ _nr = c_int(nr)
+ subfeature = _hdl.sensors_get_all_subfeatures(byref(chip), byref(feature), byref(_nr))
+ subfeature = subfeature.contents if bool(subfeature) else None
+ return subfeature, _nr.value
+
+
+def get_value(chip, subfeature_nr):
+ val = c_double()
+ err = _hdl.sensors_get_value(byref(chip), subfeature_nr, byref(val))
+ if err < 0:
+ raise Exception(strerror(err))
+ return val.value
+
+
+def set_value(chip, subfeature_nr, value):
+ """
+ @attention this function was not tested
+ """
+ val = c_double(value)
+ err = _hdl.sensors_set_value(byref(chip), subfeature_nr, byref(val))
+ if err < 0:
+ raise Exception(strerror(err))
+
+
+### Convenience API ###
+class ChipIterator:
+ def __init__(self, match=None):
+ self.match = parse_chip_name(match) if match is not None else None
+ self.nr = 0
def __iter__(self):
- number = c_int(0)
- while True:
- result_p = _get_all_subfeatures(
- byref(self.chip),
- byref(self),
- byref(number)
- )
- if not result_p:
- break
- result = result_p.contents
- result.chip = self.chip
- result.parent = self
- yield result
-
- @property
- def label(self):
- #
- # TODO Maybe this is a memory leak!
- #
- return _get_label(byref(self.chip), byref(self)).decode('utf-8')
-
- def get_value(self):
- #
- # TODO Is the first always the correct one for all feature types?
- #
- return next(iter(self)).get_value()
-
-FEATURE_P = POINTER(Feature)
-
-
-class Bus(Structure):
- TYPE_ANY = -1
- NR_ANY = -1
-
- _fields_ = [
- ('type', c_short),
- ('nr', c_short),
- ]
-
- def __str__(self):
- return (
- '*' if self.type == self.TYPE_ANY
- else _get_adapter_name(byref(self)).decode('utf-8')
- )
-
- def __repr__(self):
- return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.nr)
-
- @property
- def has_wildcards(self):
- return self.type == self.TYPE_ANY or self.nr == self.NR_ANY
-
-BUS_P = POINTER(Bus)
-
-
-class Chip(Structure):
- #
- # TODO Move common stuff into `AbstractChip` class.
- #
- _fields_ = [
- ('prefix', c_char_p),
- ('bus', Bus),
- ('addr', c_int),
- ('path', c_char_p),
- ]
-
- PREFIX_ANY = None
- ADDR_ANY = -1
-
- def __new__(cls, *args):
- result = super(Chip, cls).__new__(cls)
- if args:
- _parse_chip_name(args[0].encode('utf-8'), byref(result))
- return result
-
- def __init__(self, *_args):
- Structure.__init__(self)
- #
- # Need to bind the following to the instance so it is available in
- # `__del__()` when the interpreter shuts down.
- #
- self._free_chip_name = _free_chip_name
- self.byref = byref
+ return self
+
+ def __next__(self):
+ chip, self.nr = get_detected_chips(self.match, self.nr)
+
+ if chip is None:
+ raise StopIteration
+
+ return chip
def __del__(self):
- if self._b_needsfree_:
- self._free_chip_name(self.byref(self))
-
- def __repr__(self):
- return '<%s prefix=%r bus=%r addr=%r path=%r>' % (
- (
- self.__class__.__name__,
- self.prefix,
- self.bus,
- self.addr,
- self.path
- )
- )
-
- def __str__(self):
- buffer_size = 200
- result = create_string_buffer(buffer_size)
- used = _snprintf_chip_name(result, len(result), byref(self))
- assert used < buffer_size
- return result.value.decode('utf-8')
+ if self.match is not None:
+ free_chip_name(self.match)
+
+ def next(self): # python2 compability
+ return self.__next__()
+
+
+class FeatureIterator:
+ def __init__(self, chip):
+ self.chip = chip
+ self.nr = 0
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ feature, self.nr = get_features(self.chip, self.nr)
+
+ if feature is None:
+ raise StopIteration
+
+ return feature
+
+ def next(self): # python2 compability
+ return self.__next__()
+
+
+class SubFeatureIterator:
+ def __init__(self, chip, feature):
+ self.chip = chip
+ self.feature = feature
+ self.nr = 0
def __iter__(self):
- number = c_int(0)
- while True:
- result_p = _get_features(byref(self), byref(number))
- if not result_p:
- break
- result = result_p.contents
- result.chip = self
- yield result
-
- @property
- def adapter_name(self):
- return str(self.bus)
-
- @property
- def has_wildcards(self):
- return (
- self.prefix == self.PREFIX_ANY
- or self.addr == self.ADDR_ANY
- or self.bus.has_wildcards
- )
-
-CHIP_P = POINTER(Chip)
-
-
-_parse_chip_name = SENSORS_LIB.sensors_parse_chip_name
-_parse_chip_name.argtypes = [c_char_p, CHIP_P]
-_parse_chip_name.restype = c_int
-_parse_chip_name.errcheck = _error_check
-
-_free_chip_name = SENSORS_LIB.sensors_free_chip_name
-_free_chip_name.argtypes = [CHIP_P]
-_free_chip_name.restype = None
-
-_snprintf_chip_name = SENSORS_LIB.sensors_snprintf_chip_name
-_snprintf_chip_name.argtypes = [c_char_p, c_size_t, CHIP_P]
-_snprintf_chip_name.restype = c_int
-_snprintf_chip_name.errcheck = _error_check
-
-_get_adapter_name = SENSORS_LIB.sensors_get_adapter_name
-_get_adapter_name.argtypes = [BUS_P]
-_get_adapter_name.restype = c_char_p
-
-_get_label = SENSORS_LIB.sensors_get_label
-_get_label.argtypes = [CHIP_P, FEATURE_P]
-_get_label.restype = c_char_p
-
-_get_value = SENSORS_LIB.sensors_get_value
-_get_value.argtypes = [CHIP_P, c_int, POINTER(c_double)]
-_get_value.restype = c_int
-_get_value.errcheck = _error_check
-
-#
-# TODO sensors_set_value()
-# TODO sensors_do_chip_sets()
-#
-
-_get_detected_chips = SENSORS_LIB.sensors_get_detected_chips
-_get_detected_chips.argtypes = [CHIP_P, POINTER(c_int)]
-_get_detected_chips.restype = CHIP_P
-
-_get_features = SENSORS_LIB.sensors_get_features
-_get_features.argtypes = [CHIP_P, POINTER(c_int)]
-_get_features.restype = FEATURE_P
-
-_get_all_subfeatures = SENSORS_LIB.sensors_get_all_subfeatures
-_get_all_subfeatures.argtypes = [CHIP_P, FEATURE_P, POINTER(c_int)]
-_get_all_subfeatures.restype = SUBFEATURE_P
-
-#
-# TODO sensors_get_subfeature() ?
-#
-
-
-def iter_detected_chips(chip_name='*-*'):
- chip = Chip(chip_name)
- number = c_int(0)
- while True:
- result = _get_detected_chips(byref(chip), byref(number))
- if not result:
- break
- yield result.contents
+ return self
+
+ def __next__(self):
+ subfeature, self.nr = get_all_subfeatures(self.chip, self.feature, self.nr)
+
+ if subfeature is None:
+ raise StopIteration
+
+ return subfeature
+
+ def next(self): # python2 compability
+ return self.__next__()
\ No newline at end of file
# Description: logging for netdata python.d modules
import sys
+from time import time, strftime
DEBUG_FLAG = False
PROGRAM = ""
+LOG_COUNTER = 2
+LOG_INTERVAL = 5
+NEXT_CHECK = 0
+
+WRITE = sys.stderr.write
+FLUSH = sys.stderr.flush
def log_msg(msg_type, *args):
Print message on stderr.
:param msg_type: str
"""
- msg = "%s %s: %s" % (PROGRAM, str(msg_type), " ".join(args))
+ global LOG_COUNTER
+ if not DEBUG_FLAG:
+ LOG_COUNTER -= 1
+ now = time()
+ if LOG_COUNTER >= 0:
+ timestamp = strftime('%y-%m-%d %X')
+ msg = "%s: %s %s: %s" % (timestamp, PROGRAM, str(msg_type), " ".join(args))
+ WRITE(msg + "\n")
+ FLUSH()
- sys.stderr.write(msg + "\n")
- sys.stderr.flush()
+ global NEXT_CHECK
+ if NEXT_CHECK <= now:
+ NEXT_CHECK = now - (now % LOG_INTERVAL) + LOG_INTERVAL
+ if LOG_COUNTER < 0:
+ timestamp = strftime('%y-%m-%d %X')
+ msg = "%s: Prevented %s log messages from displaying" % (timestamp, str(0 - LOG_COUNTER))
+ WRITE(msg + "\n")
+ FLUSH()
def debug(*args):
Print message on stderr and exit.
"""
log_msg("FATAL", *args)
- sys.stdout.write('DISABLE\n')
+ # using sys.stdout causes IOError: Broken Pipe
+ print('DISABLE')
+ # sys.stdout.write('DISABLE\n')
sys.exit(1)
\ No newline at end of file
# Author: Pawel Krupa (paulfantom)
from base import SimpleService
-import lm_sensors as sensors
+import new_sensors as sensors
# default module values (can be overridden per job in `config`)
# update_every = 2
]}
}
+TYPE_MAP = {
+ 0: 'voltage',
+ 1: 'fan',
+ 2: 'temperature',
+ 3: 'power',
+ 4: 'energy',
+ 5: 'current',
+ 6: 'humidity',
+ 7: 'max_main',
+ 16: 'vid',
+ 17: 'intrusion',
+ 18: 'max_other',
+ 24: 'beep_enable'
+}
+
class Service(SimpleService):
def __init__(self, configuration=None, name=None):
def _get_data(self):
data = {}
try:
- for chip in sensors.iter_detected_chips():
- prefix = '_'.join(str(chip.path.decode()).split('/')[3:])
- lines = {}
- for feature in chip:
- data[prefix + "_" + str(feature.name.decode())] = feature.get_value() * 1000
+ for chip in sensors.ChipIterator():
+ prefix = sensors.chip_snprintf_name(chip)
+ for feature in sensors.FeatureIterator(chip):
+ sfi = sensors.SubFeatureIterator(chip, feature)
+ for sf in sfi:
+ val = sensors.get_value(chip, sf.number)
+ break
+ data[prefix + "_" + str(feature.name.decode())] = int(val * 1000)
except Exception as e:
self.error(e)
return None
return data
def _create_definitions(self):
+ prev_chip = ""
for type in ORDER:
- for chip in sensors.iter_detected_chips():
- prefix = '_'.join(str(chip.path.decode()).split('/')[3:])
- name = ""
- lines = []
- pref = str(chip.prefix.decode())
- if len(self.chips) != 0 and not any([ex.startswith(pref) for ex in self.chips]):
+ for chip in sensors.ChipIterator():
+ chip_name = sensors.chip_snprintf_name(chip)
+ if len(self.chips) != 0 and not any([chip_name.startswith(ex) for ex in self.chips]):
continue
- pref = pref + '_' + str(chip.addr)
- for feature in chip:
- try:
- float(feature.get_value())
- except ValueError:
- continue
- if feature.get_value() < 0:
+ for feature in sensors.FeatureIterator(chip):
+ sfi = sensors.SubFeatureIterator(chip, feature)
+ vals = [sensors.get_value(chip, sf.number) for sf in sfi]
+ if vals[0] == 0:
continue
- if sensors.TYPE_DICT[feature.type] == type:
- name = pref + "_" + sensors.TYPE_DICT[feature.type]
- if name not in self.order:
- options = list(CHARTS[type]['options'])
- options[1] = pref + options[1]
- self.definitions[name] = {'options': options}
- self.definitions[name]['lines'] = []
- self.order.append(name)
+ if TYPE_MAP[feature.type] == type:
+ # create chart
+ if chip_name != prev_chip:
+ name = chip_name + "_" + TYPE_MAP[feature.type]
+ if name not in self.order:
+ self.order.append(name)
+ chart_def = list(CHARTS[type]['options'])
+ chart_def[1] = chip_name + chart_def[1]
+ self.definitions[name] = {'options': chart_def}
+ self.definitions[name]['lines'] = []
line = list(CHARTS[type]['lines'][0])
- line[0] = prefix + "_" + str(feature.name.decode())
- line[1] = str(feature.label)
+ line[0] = chip_name + "_" + str(feature.name.decode())
+ line[1] = sensors.get_label(chip, feature)
self.definitions[name]['lines'].append(line)
+ prev_chip = chip_name
def check(self):
- try:
- self.chips = list(self.configuration['chips'])
- except (KeyError, TypeError):
- self.error("No path to log specified. Using all chips.")
- try:
- global ORDER
- ORDER = list(self.configuration['types'])
- except (KeyError, TypeError):
- self.error("No path to log specified. Using all sensor types.")
try:
sensors.init()
except Exception as e:
self.error(e)
return False
+
try:
self._create_definitions()
- except:
- return False
-
- if len(self.definitions) == 0:
- self.error("No sensors found")
+ except Exception as e:
+ self.error(e)
return False
-
- return True
+ return True
\ No newline at end of file