.cproject
.idea/
.project
-CMakeLists.txt
README
TODO.md
asan_symbolize.py
system/netdata-openrc
system/netdata-init-d
+system/netdata.logrotate
netdata-installer.log
netdata-uninstaller.sh
gmon.out
gmon.txt
-
apps.plugin-profiler.sh
+
+CMakeCache.txt
+CMakeFiles/
+cmake_install.cmake
--- /dev/null
+language: c
+compiler:
+ - gcc
+ - clang
+before_install:
+ - sudo apt-get update -qq
+ - sudo apt-get install -qq automake make zlib1g-dev
+script:
+ # default build
+ - ./autogen.sh && ./configure && make -j4
+
+ # test installer
+ - fakeroot ./netdata-installer.sh --install $HOME --dont-wait --dont-start-it
--- /dev/null
+
+# This file is just a hack to make netdata
+# open in Clion
+# It cannot build netdata
+
+cmake_minimum_required(VERSION 3.3)
+project(netdata)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+
+set(NETDATA_SOURCE_FILES
+ src/appconfig.c
+ src/appconfig.h
+ src/avl.c
+ src/avl.h
+ src/common.c
+ src/common.h
+ src/daemon.c
+ src/daemon.h
+ src/dictionary.c
+ src/dictionary.h
+ src/global_statistics.c
+ src/global_statistics.h
+ src/log.c
+ src/log.h
+ src/main.c
+ src/main.h
+ src/plugin_checks.c
+ src/plugin_checks.h
+ src/plugin_idlejitter.c
+ src/plugin_idlejitter.h
+ src/plugin_nfacct.c
+ src/plugin_nfacct.h
+ src/plugin_proc.c
+ src/plugin_proc.h
+ src/plugins_d.c
+ src/plugins_d.h
+ src/plugin_tc.c
+ src/plugin_tc.h
+ src/popen.c
+ src/popen.h
+ src/proc_diskstats.c
+ src/procfile.c
+ src/procfile.h
+ src/proc_interrupts.c
+ src/proc_loadavg.c
+ src/proc_meminfo.c
+ src/proc_net_dev.c
+ src/proc_net_ip_vs_stats.c
+ src/proc_net_netstat.c
+ src/proc_net_rpc_nfsd.c
+ src/proc_net_snmp6.c
+ src/proc_net_snmp.c
+ src/proc_net_stat_conntrack.c
+ src/proc_net_stat_synproxy.c
+ src/proc_softirqs.c
+ src/proc_stat.c
+ src/proc_sys_kernel_random_entropy_avail.c
+ src/proc_vmstat.c
+ src/rrd2json.c
+ src/rrd2json.h
+ src/rrd.c
+ src/rrd.h
+ src/storage_number.c
+ src/storage_number.h
+ src/sys_kernel_mm_ksm.c
+ src/unit_test.c
+ src/unit_test.h
+ src/url.c
+ src/url.h
+ src/web_buffer.c
+ src/web_buffer.h
+ src/web_client.c
+ src/web_client.h
+ src/web_server.c
+ src/web_server.h
+ config.h)
+
+set(APPS_PLUGIN_SOURCE_FILES
+ src/appconfig.c
+ src/appconfig.h
+ src/apps_plugin.c
+ src/avl.c
+ src/avl.h
+ src/common.c
+ src/common.h
+ src/log.c
+ src/log.h
+ config.h)
+
+add_definitions(-DHAVE_CONFIG_H -DNETDATA_INTERNAL_CHECKS=1 -DCACHE_DIR="/tmp" -DCONFIG_DIR="/tmp" -DLOG_DIR="/tmp" -DPLUGINS_DIR="/tmp" -DWEB_DIR="/tmp")
+
+add_executable(netdata ${NETDATA_SOURCE_FILES})
+add_executable(apps.plugin ${APPS_PLUGIN_SOURCE_FILES})
+netdata (1.1.0) - 2016-04-20
+
+ Dozens of commits that improve netdata in several ways:
+
+ - Data collection: added IPv6 monitoring
+ - Data collection: added SYNPROXY DDoS protection monitoring
+ - Data collection: apps.plugin: added charts for users and user groups
+ - Data collection: apps.plugin: grouping of processes now support patterns
+ - Data collection: apps.plugin: now it is faster, after the new features added
+ - Data collection: better auto-detection of partitions for disk monitoring
+ - Data collection: better fireqos intergation for QoS monitoring
+ - Data collection: squid monitoring now uses squidclient
+ - Data collection: SNMP monitoring now supports 64bit counters
+ - API: fixed issues in CSV output generation
+ - API: netdata can now be restricted to listen on a specific IP
+ - Core and apps.plugin: error log flood protection
+ - Dashboard: better error handling when the netdata server is unreachable
+ - Dashboard: each chart now has a toolbox
+ - Dashboard: on-line help support
+ - Dashboard: check for netdata updates button
+ - Dashboard: added example /tv.html dashboard
+ - Packaging: now compiles with musl libc (alpine linux)
+ - Packaging: added debian packaging
+ - Packaging: support non-root installations
+ - Packaging: the installer generates uninstall script
+
netdata (1.0.0) - 2016-03-22
- first public release
src \
system \
web \
+ contrib \
$(NULL)
dist_noinst_DATA = netdata.spec
# netdata
-#### 180.000+ views, 50.000+ visitors, 15.000+ downloads, 8.000+ github stars, 400+ forks, 7 days!
+#### 230.000+ views, 62.000+ visitors, 18.500+ downloads, 9.500+ github stars, 500+ forks, 14 days!
-And it still runs with 1.000+ git downloads... per day!
+And it still runs with 700+ git downloads... per day!
-**[check what our users say about netdata](https://github.com/firehol/netdata/issues/148)**.
+**[Check what our users say about netdata](https://github.com/firehol/netdata/issues/148)**.
Thank you!
-#!/bin/sh
+#!/bin/bash
# _update_every is a special variable - it holds the number of seconds
# between the calls of the _update() function
-#!/bin/sh
+#!/bin/bash
# the URL to download apache status info
apache_url="http://127.0.0.1:80/server-status?auto"
-#!/bin/sh
+#!/bin/bash
# if this chart is called X.chart.sh, then all functions and global variables
# must start with X_
-#!/bin/sh
+#!/bin/bash
# http://dev.mysql.com/doc/refman/5.0/en/server-status-variables.html
#
-#!/bin/sh
+#!/bin/bash
# if this chart is called X.chart.sh, then all functions and global variables
# must start with X_
--- /dev/null
+#!/bin/bash
+
+# if this chart is called X.chart.sh, then all functions and global variables
+# must start with X_
+
+# first, you need open php-fpm status in php-fpm.conf
+# second, you need add status location in nginx.conf
+# you can see, https://easyengine.io/tutorials/php/fpm-status-page/
+
+declare -A phpfpm_urls=()
+
+# _update_every is a special variable - it holds the number of seconds
+# between the calls of the _update() function
+phpfpm_update_every=
+phpfpm_priority=60000
+
+declare -a phpfpm_response=()
+phpfpm_pool=""
+phpfpm_start_time=""
+phpfpm_start_since=0
+phpfpm_accepted_conn=0
+phpfpm_listen_queue=0
+phpfpm_max_listen_queue=0
+phpfpm_listen_queue_len=0
+phpfpm_idle_processes=0
+phpfpm_active_processes=0
+phpfpm_total_processes=0
+phpfpm_max_active_processes=0
+phpfpm_max_children_reached=0
+phpfpm_slow_requests=0
+phpfpm_get() {
+ url=$1
+ phpfpm_response=($(curl -s "${url}"))
+ [ $? -ne 0 -o "${#phpfpm_response[@]}" -eq 0 ] && return 1
+
+ if [[ "${phpfpm_response[0]}" != "pool:" \
+ || "${phpfpm_response[2]}" != "process" \
+ || "${phpfpm_response[5]}" != "start" \
+ || "${phpfpm_response[12]}" != "accepted" \
+ || "${phpfpm_response[15]}" != "listen" \
+ || "${phpfpm_response[16]}" != "queue:" \
+ || "${phpfpm_response[26]}" != "idle" \
+ || "${phpfpm_response[29]}" != "active" \
+ || "${phpfpm_response[32]}" != "total" \
+ || "${phpfpm_response[43]}" != "slow" \
+ ]]
+ then
+ echo >&2 "phpfpm: invalid response from phpfpm status server: ${phpfpm_response[*]}"
+ return 1
+ fi
+
+ phpfpm_pool="${phpfpm_response[1]}"
+ phpfpm_start_time="${phpfpm_response[7]} ${phpfpm_response[8]}"
+ phpfpm_start_since="${phpfpm_response[11]}"
+ phpfpm_accepted_conn="${phpfpm_response[14]}"
+ phpfpm_listen_queue="${phpfpm_response[17]}"
+ phpfpm_max_listen_queue="${phpfpm_response[21]}"
+ phpfpm_listen_queue_len="${phpfpm_response[25]}"
+ phpfpm_idle_processes="${phpfpm_response[28]}"
+ phpfpm_active_processes="${phpfpm_response[31]}"
+ phpfpm_total_processes="${phpfpm_response[34]}"
+ phpfpm_max_active_processes="${phpfpm_response[38]}"
+ phpfpm_max_children_reached="${phpfpm_response[42]}"
+ phpfpm_slow_requests="${phpfpm_response[45]}"
+
+ if [[ -z "${phpfpm_pool}" \
+ || -z "${phpfpm_start_time}" \
+ || -z "${phpfpm_start_since}" \
+ || -z "${phpfpm_accepted_conn}" \
+ || -z "${phpfpm_listen_queue}" \
+ || -z "${phpfpm_max_listen_queue}" \
+ || -z "${phpfpm_listen_queue_len}" \
+ || -z "${phpfpm_idle_processes}" \
+ || -z "${phpfpm_active_processes}" \
+ || -z "${phpfpm_total_processes}" \
+ || -z "${phpfpm_max_active_processes}" \
+ || -z "${phpfpm_max_children_reached}" \
+ || -z "${phpfpm_slow_requests}" \
+ ]]
+ then
+ echo >&2 "phpfpm: empty values got from phpfpm status server: ${phpfpm_response[*]}"
+ return 1
+ fi
+
+ return 0
+}
+
+# _check is called once, to find out if this chart should be enabled or not
+phpfpm_check() {
+ if [ ${#phpfpm_urls[@]} -eq 0 ]; then
+ phpfpm_urls[local]="http://localhost/status"
+ fi
+
+ local m
+ for m in "${!phpfpm_urls[@]}"
+ do
+ phpfpm_get "${phpfpm_urls[$m]}"
+ if [ $? -ne 0 ]; then
+ echo >&2 "phpfpm: cannot find status on URL '${phpfpm_url[$m]}'. Please set phpfpm_urls[$m]='http://localhost/status' in $confd/phpfpm.conf"
+ unset phpfpm_urls[$m]
+ continue
+ fi
+ done
+
+ if [ ${#phpfpm_urls[@]} -eq 0 ]; then
+ echo >&2 "phpfpm: no phpfpm servers found. Please set phpfpm_urls[name]='url' to whatever needed to get status to the phpfpm server, in $confd/phpfpm.conf"
+ return 1
+ fi
+
+ # this should return:
+ # - 0 to enable the chart
+ # - 1 to disable the chart
+
+ return 0
+}
+
+# _create is called once, to create the charts
+phpfpm_create() {
+ local m
+ for m in "${!phpfpm_urls[@]}"
+ do
+ cat <<EOF
+CHART phpfpm_$m.connections '' "PHP-FPM Active Connections" "connections" phpfpm phpfpm.connections line $[phpfpm_priority + 1] $phpfpm_update_every
+DIMENSION active '' absolute 1 1
+DIMENSION maxActive 'max active' absolute 1 1
+DIMENSION idle '' absolute 1 1
+
+CHART phpfpm_$m.requests '' "PHP-FPM Requests" "requests/s" phpfpm phpfpm.requests line $[phpfpm_priority + 2] $phpfpm_update_every
+DIMENSION requests '' incremental 1 1
+
+CHART phpfpm_$m.performance '' "PHP-FPM Performance" "status" phpfpm phpfpm.performance line $[phpfpm_priority + 3] $phpfpm_update_every
+DIMENSION reached 'max children reached' absolute 1 1
+DIMENSION slow 'slow requests' absolute 1 1
+EOF
+ done
+
+ return 0
+}
+
+# _update is called continiously, to collect the values
+phpfpm_update() {
+ # the first argument to this function is the microseconds since last update
+ # pass this parameter to the BEGIN statement (see bellow).
+
+ # do all the work to collect / calculate the values
+ # for each dimension
+ # remember: KEEP IT SIMPLE AND SHORT
+
+ local m
+ for m in "${!phpfpm_urls[@]}"
+ do
+ phpfpm_get "${phpfpm_urls[$m]}"
+ if [ $? -ne 0 ]; then
+ continue
+ fi
+
+ # write the result of the work.
+ cat <<EOF
+BEGIN phpfpm_$m.connections $1
+SET active = $[phpfpm_active_processes]
+SET maxActive = $[phpfpm_max_active_processes]
+SET idle = $[phpfpm_idle_processes]
+END
+BEGIN phpfpm_$m.requests $1
+SET requests = $[phpfpm_accepted_conn]
+END
+BEGIN phpfpm_$m.performance $1
+SET reached = $[phpfpm_max_children_reached]
+SET slow = $[phpfpm_slow_requests]
+END
+EOF
+ done
+
+ return 0
+}
# group_name: process1 process2 process3 ...
#
# The process names are the same to the ones returned by: ps -e
+# or /proc/PID/stat
#
-# If a group_name starts with a -, the dimension will be hidden (cpu chart only)
+# To add process names with spaces, enclose them in quotes (single or double)
+# example: 'Plex Media Serv' "my other process"
#
+# Wildcard support:
+# You can add an asterisk (*) at the beginning and/or the end of a process name:
+# *name suffix mode: will search for processes ending with 'name' (/proc/PID/stat)
+# name* prefix mode: will search for processes beginning with 'name' (/proc/PID/stat)
+# *name* substring mode: will search for 'name' in the whole command line (/proc/PID/cmdline)
+#
+# If you enter even just one *name* (substring), apps.plugin will process
+# /proc/PID/cmdline for all processes, on every iteration.
+#
+# To add process names with single quotes, enclose them in double quotes
+# example: "process with this ' single quote"
+#
+# To add process names with double quotes, enclose them in single quotes:
+# example: 'process with this " double quote'
+#
+# If a group name starts with a -, the dimension will be hidden (cpu chart only)
+#
+# If any process name starts with a +, debugging will be enabled for it
+# (debugging produces a lot of output - do not enable it in production systems)
+#
+# You can add any number of groups you like. Only the ones found running will
+# affect the charts generated. However, producing charts with hundreds of
+# dimensions may slow down your web browser.
-compile: cc1 cc1plus as gcc ld make automake autoconf git
+compile: cc1 cc1plus as gcc* ld make automake autoconf git
rsync: rsync
-media: mplayer vlc xine mediatomb omxplayer omxplayer.bin kodi kodi.bin xbmc xbmc.bin mediacenter eventlircd
-squid: squid squid2 squid3 c-icap
-apache: apache apache2
-mysql: mysqld mysql
+media: mplayer vlc xine mediatomb omxplayer* kodi* xbmc* mediacenter eventlircd
+squid: squid* c-icap
+apache: apache*
+mysql: mysql*
asterisk: asterisk
-opensips: opensips opensips-mi-pro stund
-radius: radiusd radiusclient
-fail2ban: fail2ban-server
+opensips: opensips* stund
+radius: radius*
+fail2ban: fail2ban*
mail: dovecot imapd pop3d
postfix: master
nginx: nginx
lighttpd: lighttpd
ftpd: proftpd in.tftpd
samba: smbd nmbd winbindd
-nfs: rpcbind rpc.statd rpc.idmapd rpc.mountd nfsd4 nfsd4_callbacks nfsd nfsiod
-ssh: ssh sshd scp
+nfs: rpcbind rpc.* nfs*
+ssh: ssh* scp
X: X lightdm xdm pulseaudio gkrellm
-xfce: xfwm4 xfdesktop xfce4-appfinder Thunar xfsettingsd xfce4-panel
-gnome: gnome-session gdm gconfd-2 gnome-terminal gnome-screensaver gnome-settings-daemon
+xfce: xfwm4 xfdesktop xfce* Thunar xfsettingsd
+gnome: gnome-* gdm gconfd-2
named: named rncd
-clam: clamd freshclam
-cups: cupsd cups-browsed
-ntp: ntpq ntpd
-deluge: deluge deluged
-vbox: vboxwebsrv VBoxXPCOMIPCD VBoxSVC
-log: ulogd syslogd syslog-ng rsyslogd logrotate
-nms: snmpd vnstatd smokeping zabbix_agentd monit munin-node mon openhpid
-ppp: ppp pppd pptpd pptpctrl
+clam: clam* *clam
+cups: cups*
+ntp: ntp*
+deluge: deluge*
+vbox: vbox* VBox*
+log: ulogd syslog* rsyslog* logrotate
+nms: snmpd vnstatd smokeping zabbix* monit munin* mon openhpid
+ppp: ppp* pptp*
inetd: inetd xinetd
openvpn: openvpn
cjdns: cjdroute
cron: cron atd
ha: corosync hs_logd ha_logd stonithd
-ipvs: ipvs_syncmaster ipvs_syncbackup
+ipvs: ipvs_*
kernel: kthreadd kauditd lockd khelper kdevtmpfs khungtaskd rpciod fsnotify_mark kthrotld iscsi_eh deferwq
-netdata: netdata apps.plugin charts.d.plugin
+netdata: netdata
crsproxy: crsproxy
wifi: hostapd wpa_supplicant
-system: systemd-journal systemd-udevd systemd-logind udisks-glue udisks-daemon udevd udevd connmand ipv6_addrconf dbus-daemon
+system: systemd* udisks* udevd connmand ipv6_addrconf dbus-*
ksmd: ksmd
-lxc: lxc-start
-zfs-spl: spl_kmem_cache spl_system_task spl_dynamic_tas
-zfs-posix: z_import z_unmount z_rd_iss z_rd_int_ z_wr_iss z_wr_int z_fr_iss z_fr_int z_cl_iss z_ioctl_iss z_zvol z_iput
-zfs-txg: txg_quiesce txg_sync zil_clean
-zfs-arc: arc_prune arc_reclaim arc_user_evicts l2arc_feed
+lxc: lxc*
+zfs-spl: spl_*
+zfs-posix: z_*
+zfs-txg: txg_* zil_*
+zfs-arc: arc_* l2arc*
AC_PREREQ(2.60)
define([VERSION_MAJOR], [1])
-define([VERSION_MINOR], [0])
+define([VERSION_MINOR], [1])
define([VERSION_FIX], [1])
define([VERSION_NUMBER], VERSION_MAJOR[.]VERSION_MINOR[.]VERSION_FIX)
define([VERSION_SUFFIX], [_master])
dnl Set to "1" for a first RPM release of a new version
-PACKAGE_RPM_RELEASE="0.0.$(echo VERSION_SUFFIX | sed 's/^_//')"
+PACKAGE_RPM_RELEASE="0.0.$(echo VERSION_SUFFIX | sed s/^_//)"
AC_INIT([netdata], VERSION_NUMBER[]VERSION_SUFFIX)
src/Makefile
system/Makefile
web/Makefile
+ contrib/Makefile
])
AC_OUTPUT
--- /dev/null
+MAINTAINERCLEANFILES= $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+ README.md \
+ debian/copyright \
+ debian/netdata.conf \
+ debian/source/format \
+ debian/compat \
+ debian/netdata.install \
+ debian/netdata.lintian-overrides \
+ debian/rules \
+ debian/netdata.docs \
+ debian/netdata.default \
+ debian/control \
+ debian/netdata.postinst.in \
+ debian/netdata.service \
+ debian/changelog \
+ debian/netdata.postrm \
+ $(NULL)
+
+dist_noinst_SCRIPTS = \
+ debian/netdata.init \
+ $(NULL)
--- /dev/null
+# netdata contrib
+
+## Building .deb packages
+
+The `contrib/debian/` directory contains basic rules to build a
+Debian package. It has been tested on Debian Jessie and Wheezy,
+but should work, possibly with minor changes, if you have other
+dpkg-based systems such as Ubuntu or Mint.
+
+To build netdata for a Debian Jessie system, the debian directory
+has to be available in the root of the netdata source. The easiest
+way to do this is with a symlink:
+
+ ~/netdata$ ln -s contrib/debian
+
+Then build the debian package:
+
+ ~/netdata$ dpkg-buildpackage -us -uc -rfakeroot
+
+This should give a package that can be installed in the parent
+directory, which you can install manually with dpkg.
+
+ ~/netdata$ ls ../*.deb
+ ../netdata_1.0.0_amd64.deb
+ ~/netdata$ sudo dpkg -i ../netdata_1.0.0_amd64.deb
+
+
+### Building for a Debian system without systemd
+
+The included packaging is designed for modern Debian systems that
+are based on systemd. To build non-systemd packages (for example,
+for Debian wheezy), you will need to make a couple of minor
+updates first.
+
+* edit `contrib/debian/rules` and adjust the `dh` rule near the
+ top to remove systemd (see comments in that file).
+
+* edit `contrib/debian/control`: remove `dh-systemd` from the
+ Build-Depends list, and add `pkg-config` to it.
+
+Then proceed as the main instructions above.
+
+### Reinstalling netdata
+
+The recommended way to upgrade netdata packages built from this
+source is to remove the current package from your system, then
+install the new package. Upgrading on wheezy is known to not
+work cleanly; Jessie may behave as expected.
+
--- /dev/null
+netdata (1.0.0) UNRELEASED; urgency=medium
+
+ * Initial release.
+
+ -- Matthew Newton <mcn4@leicester.ac.uk> Fri, 01 Apr 2016 17:24:11 +0100
--- /dev/null
+Source: netdata
+Build-Depends: debhelper (>= 9),
+ dh-autoreconf,
+ dh-systemd (>= 1.5),
+ dpkg-dev (>= 1.13.19),
+ zlib1g-dev
+Section: net
+Priority: optional
+Maintainer: Costa Tsaousis <costa@tsaousis.gr>
+Standards-Version: 3.9.6
+Homepage: https://github.com/firehol/netdata/wiki
+
+Package: netdata
+Architecture: any
+Depends: adduser,
+ libcap2-bin (>= 1:2.0),
+ lsb-base (>= 3.1-23.2),
+ ${misc:Depends},
+ ${shlibs:Depends}
+Description: real-time charts for system monitoring
+ Netdata is a daemon that collects data in realtime (per second)
+ and presents a web site to view and analyze them. The presentation
+ is also real-time and full of interactive charts that precisely
+ render all collected values.
--- /dev/null
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: Netdata
+Upstream-Contact: Costa Tsaousis <costa@tsaousis.gr>
+Source: https://github.com/firehol/netdata
+
+Files: *
+Copyright: 2014-2016, Costa Tsaousis
+License: GPL-3+
+ On Debian systems, the complete text of the GNU General Public
+ License version 3 can be found in /usr/share/common-licenses/GPL-3.
--- /dev/null
+# NetData Configuration
+
+# The current full configuration can be retrieved from the running
+# server at the URL
+#
+# http://localhost:19999/netdata.conf
+#
+# for example:
+#
+# wget -O /etc/netdata/netdata.conf http://localhost:19999/netdata.conf
+#
+
+[global]
+ run as user = netdata
+ web files owner = root
+ web files group = netdata
--- /dev/null
+# Extra arguments to pass to netdata
+#
+#EXTRA_OPTS=""
+
--- /dev/null
+#!/bin/sh
+# Start/stop the netdata daemon.
+#
+### BEGIN INIT INFO
+# Provides: netdata
+# Required-Start: $remote_fs
+# Required-Stop: $remote_fs
+# Should-Start: $network
+# Should-Stop: $network
+# Default-Start: 2 3 4 5
+# Default-Stop:
+# Short-Description: Real-time charts for system monitoring
+# Description: Netdata is a daemon that collects data in realtime (per second)
+# and presents a web site to view and analyze them. The presentation
+# is also real-time and full of interactive charts that precisely
+# render all collected values.
+### END INIT INFO
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+DESC="netdata daemon"
+NAME=netdata
+DAEMON=/usr/sbin/netdata
+PIDFILE=/var/run/netdata/netdata.pid
+SCRIPTNAME=/etc/init.d/"$NAME"
+
+test -f $DAEMON || exit 0
+
+. /lib/lsb/init-functions
+
+[ -r /etc/default/netdata ] && . /etc/default/netdata
+
+case "$1" in
+start) log_daemon_msg "Starting real-time system monitoring" "netdata"
+ start_daemon -p $PIDFILE $DAEMON $EXTRA_OPTS
+ log_end_msg $?
+ ;;
+stop) log_daemon_msg "Stopping real-time system monitoring" "netdata"
+ killproc -p $PIDFILE $DAEMON
+ RETVAL=$?
+ [ $RETVAL -eq 0 ] && [ -e "$PIDFILE" ] && rm -f $PIDFILE
+ log_end_msg $RETVAL
+ # wait for plugins to exit
+ sleep 1
+ ;;
+restart|force-reload) log_daemon_msg "Restarting real-time system monitoring" "netdata"
+ $0 stop
+ $0 start
+ ;;
+status)
+ status_of_proc -p $PIDFILE $DAEMON $NAME && exit 0 || exit $?
+ ;;
+*) log_action_msg "Usage: /etc/init.d/cron {start|stop|status|restart|force-reload}"
+ exit 2
+ ;;
+esac
+exit 0
--- /dev/null
+debian/netdata.conf /etc/netdata/
--- /dev/null
+
+# See Debian policy 10.9. apps.plugin has extra capabilities, so don't let
+# normal users run it.
+netdata: non-standard-executable-perm usr/lib/*/netdata/plugins.d/apps.plugin 0754 != 0755
+
+
+# FontAwesome is at least in the fonts-font-awesome package, but this is
+# not available in wheezy. glyphicons-halflings-regular isn't currently in
+# a Debian package. Therefore don't complain about shipping them with netdata
+# for the time being.
+netdata: duplicate-font-file usr/share/netdata/fonts/*
+netdata: font-in-non-font-package usr/share/netdata/fonts/*
+
+# Files here are marked as conffiles so that local updates to the html files
+# isn't clobbered on upgrade.
+netdata: non-etc-file-marked-as-conffile var/lib/netdata/www/*
--- /dev/null
+#! /bin/sh
+
+set -e
+
+case "$1" in
+ configure)
+ if [ -z "$2" ]; then
+ if ! getent group netdata >/dev/null; then
+ addgroup --quiet --system netdata
+ fi
+
+ if ! getent passwd netdata >/dev/null; then
+ adduser --quiet --system --ingroup netdata --home /var/lib/netdata --no-create-home netdata
+ fi
+
+ if ! dpkg-statoverride --list /var/lib/netdata >/dev/null 2>&1; then
+ dpkg-statoverride --update --add root netdata 0755 /var/lib/netdata
+ fi
+
+ if ! dpkg-statoverride --list /var/lib/netdata/www >/dev/null 2>&1; then
+ dpkg-statoverride --update --add root netdata 0755 /var/lib/netdata/www
+ fi
+
+ if ! dpkg-statoverride --list /var/cache/netdata >/dev/null 2>&1; then
+ dpkg-statoverride --update --add netdata netdata 0755 /var/cache/netdata
+ fi
+
+ fi
+
+ chown -R root:netdata /usr/share/netdata/*
+ chown -R root:netdata /usr/lib/@DEB_HOST_MULTIARCH@/netdata/plugins.d
+ setcap cap_dac_read_search,cap_sys_ptrace+ep /usr/lib/@DEB_HOST_MULTIARCH@/netdata/plugins.d/apps.plugin
+
+#PERMS#
+ ;;
+esac
+
+#DEBHELPER#
+
+exit 0
+
--- /dev/null
+#! /bin/sh
+
+set -e
+
+case "$1" in
+ remove)
+ ;;
+
+ purge)
+ if dpkg-statoverride --list | grep -qw /var/cache/netdata; then
+ dpkg-statoverride --remove /var/cache/netdata
+ fi
+
+ if dpkg-statoverride --list | grep -qw /var/lib/netdata/www; then
+ dpkg-statoverride --remove /var/lib/netdata/www
+ fi
+
+ if dpkg-statoverride --list | grep -qw /var/lib/netdata; then
+ dpkg-statoverride --remove /var/lib/netdata
+ fi
+
+ if getent passwd netdata >/dev/null; then
+ if [ -x /usr/sbin/deluser ]; then
+ deluser --quiet --system netdata || echo "Unable to remove netdata user"
+ fi
+ fi
+
+ if getent group netdata >/dev/null; then
+ if [ -x /usr/sbin/delgroup ]; then
+ delgroup --quiet --system netdata || echo "Unable to remove netdata group"
+ fi
+ fi
+
+ ;;
+
+ *)
+ ;;
+esac
+
+#DEBHELPER#
+
+exit 0
+
--- /dev/null
+[Unit]
+Description=netdata real-time system monitoring
+After=network.target
+
+[Service]
+Type=simple
+EnvironmentFile=-/etc/default/netdata
+ExecStart=/usr/sbin/netdata -nd $EXTRA_OPTS
+TimeoutStopSec=30
+Restart=always
+RestartSec=5
+
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+#!/usr/bin/make -f
+
+# Find the arch we are building for, as this determines
+# the location of plugins in /usr/lib
+DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
+TOP = $(CURDIR)/debian/netdata
+
+%:
+ # For jessie and beyond
+ #
+ dh $@ --with autoreconf,systemd
+
+ # For wheezy or other non-systemd distributions use the following. You
+ # should also see contrib/README.md which gives details of updates to
+ # make to debian/control.
+ #
+ #dh $@ --with autoreconf
+
+override_dh_auto_configure:
+ dh_auto_configure -- --with-math --with-webdir=/var/lib/netdata/www
+
+debian/%.postinst: debian/%.postinst.in
+ sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' $< > $@
+
+override_dh_install: debian/netdata.postinst
+ dh_install
+
+ # Remove unneeded .keep files
+ #
+ find "$(TOP)" -name .keep -exec rm '{}' ';'
+
+ # Move files that local user shouldn't be editing to /usr/share/netdata
+ #
+ mkdir -p "$(TOP)/usr/share/netdata"
+ for D in $$(find "$(TOP)/var/lib/netdata/www/" -maxdepth 1 -type d -printf '%f '); do \
+ echo Relocating $$D; \
+ mv "$(TOP)/var/lib/netdata/www/$$D" "$(TOP)/usr/share/netdata/$$D"; \
+ ln -s "/usr/share/netdata/$$D" "$(TOP)/var/lib/netdata/www/$$D"; \
+ done
+
+ # Update postinst to set correct group for www files on installation.
+ # Should probably be dpkg-statoverride really, but that gets *really*
+ # messy. We also set all web files in /var as conffiles so an upgrade
+ # doesn't splat them.
+ #
+ for D in $$(find "$(TOP)/var/lib/netdata/www/" -maxdepth 1 -type f -printf '%f '); do \
+ echo Updating postinst for $$D; \
+ sed -i "s/^#PERMS#/chgrp netdata \/var\/lib\/netdata\/www\/$$D\n#PERMS#/g" \
+ $(CURDIR)/debian/netdata.postinst; \
+ echo "/var/lib/netdata/www/$$D" >> $(CURDIR)/debian/netdata.conffiles; \
+ done
+ sed -i "/^#PERMS#/d" $(CURDIR)/debian/netdata.postinst
+
+override_dh_installdocs:
+ dh_installdocs
+
+ # Docs should not be under /usr/lib
+ #
+ mv $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/plugins.d/README.md \
+ $(TOP)/usr/share/doc/netdata/README.plugins.md
+ mv $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/charts.d/README.md \
+ $(TOP)/usr/share/doc/netdata/README.charts.md
+
+ # This doc is currently empty, so no point installing it.
+ #
+ rm $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/node.d/README.md
+
+override_dh_fixperms:
+ dh_fixperms
+
+ # apps.plugin should only be runnable by the netdata user. It will be
+ # given extra capabilities in the postinst script.
+ #
+ chmod 0754 $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/plugins.d/apps.plugin
+
+override_dh_installlogrotate:
+ cp system/netdata.logrotate debian/netdata.logrotate
+ dh_installlogrotate
+
+override_dh_clean:
+ dh_clean
+
+ # Tidy up copied/generated files
+ #
+ -[ -r $(CURDIR)/debian/netdata.logrotate ] && rm $(CURDIR)/debian/netdata.logrotate
+ -[ -r $(CURDIR)/debian/netdata.postinst ] && rm $(CURDIR)/debian/netdata.postinst
+ -[ -r $(CURDIR)/debian/netdata.conffiles ] && rm $(CURDIR)/debian/netdata.conffiles
--- /dev/null
+3.0 (native)
"
: ${NETDATA_USER:=netdata}
+: ${NETDATA_GROUP:=netdata}
pkg_setup() {
linux-info_pkg_setup
src_install() {
default
- fowners ${NETDATA_USER} /var/log/netdata
+ fowners ${NETDATA_USER}:${NETDATA_GROUP} /var/log/netdata
+ fowners ${NETDATA_USER}:${NETDATA_GROUP} /var/cache/netdata
- chown -Rc ${NETDATA_USER} "${ED}"/usr/share/${PN} || die
+ chown -Rc ${NETDATA_USER}:${NETDATA_GROUP} "${ED}"/usr/share/${PN} || die
cat >> "${T}"/${PN}-sysctl <<- EOF
kernel.mm.ksm.run = 1
#!/bin/bash
+# reload the user profile
+[ -f /etc/profile ] && . /etc/profile
+
LC_ALL=C
# you can set CFLAGS before running installer
BANNER
-if [ ! "${UID}" = 0 -o "$1" = "-h" -o "$1" = "--help" ]
+if [ "${UID}" -ne 0 ]
then
- echo >&2
- echo >&2 "You have to run netdata as root."
- echo >&2 "The netdata daemon will drop priviliges"
- echo >&2 "but you have to start it as root."
- echo >&2
- exit 1
+ if [ -z "${NETDATA_PREFIX}" ]
+ then
+ cat <<NONROOTNOPREFIX
+
+Sorry! This will wrong!
+
+You are attempting to install netdata as non-root, but you plan to install it
+in system paths.
+
+Please set an installation prefix, like this:
+
+ $0 ${@} --install /tmp
+
+or, run the installer as root:
+
+ sudo $0 ${@}
+
+We suggest to install it as root, or certain data collectors will not be able
+to work. Netdata drops root privileges when running. So, if you plan to keep
+it, install it as root to get the full functionality.
+
+NONROOTNOPREFIX
+ exit 1
+
+ else
+ cat <<NONROOT
+
+IMPORTANT:
+You are about to install netdata as a non-root user.
+Netdata will work, but a few data collection modules that
+require root access will fail.
+
+If you installing permanently on your system, run the
+installer like this:
+
+ sudo $0 ${@}
+
+NONROOT
+ fi
fi
have_autotools=
else
cat <<-"EOF"
+ -------------------------------------------------------------------------------
+ autotools 2.60 or later is required
+
Sorry, you do not seem to have autotools 2.60 or later, which is
required to build from the git sources of netdata.
fi
fi
-# reload the profile
-[ -f /etc/profile ] && . /etc/profile
-
build_error() {
cat <<EOF
3. If your system cannot find ZLIB, although it is installed
run me with the option: --zlib-is-really-here
+
If you still cannot get it to build, ask for help at github:
https://github.com/firehol/netdata/issues
}
run() {
+ printf >&2 "\n"
printf >&2 ":-----------------------------------------------------------------------------\n"
printf >&2 "Running command:\n"
printf >&2 "\n"
if [ "$have_autotools" ]
then
- echo >&2 "Running ./autogen.sh ..."
run ./autogen.sh || exit 1
fi
-echo >&2 "Running ./configure ..."
run ./configure \
--prefix="${NETDATA_PREFIX}/usr" \
--sysconfdir="${NETDATA_PREFIX}/etc" \
echo >&2 "Compiling netdata ..."
run make || exit 1
+# backup user configurations
+for x in apps_groups.conf charts.d.conf
+do
+ if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}" ]
+ then
+ cp -p "${NETDATA_PREFIX}/etc/netdata/${x}" "${NETDATA_PREFIX}/etc/netdata/${x}.installer_backup"
+ fi
+done
+
echo >&2 "Installing netdata ..."
run make install || exit 1
-echo >&2 "Adding netdata user group ..."
-getent group netdata > /dev/null || run groupadd -r netdata
+# restore user configurations
+for x in apps_groups.conf charts.d.conf
+do
+ if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}.installer_backup" ]
+ then
+ cp -p "${NETDATA_PREFIX}/etc/netdata/${x}.installer_backup" "${NETDATA_PREFIX}/etc/netdata/${x}"
+ fi
+done
-echo >&2 "Adding netdata user account ..."
-getent passwd netdata > /dev/null || run useradd -r -g netdata -c netdata -s /sbin/nologin -d / netdata
+if [ ${UID} -eq 0 ]
+ then
+ echo >&2 "Adding netdata user group ..."
+ getent group netdata > /dev/null || run groupadd -r netdata
+ echo >&2 "Adding netdata user account ..."
+ getent passwd netdata > /dev/null || run useradd -r -g netdata -c netdata -s /sbin/nologin -d / netdata
+fi
# -----------------------------------------------------------------------------
[ ! "${UID}" = "0" ] && defuser="${USER}"
NETDATA_USER="$( config_option "run as user" "${defuser}" )"
+NETDATA_WEB_USER="$( config_option "web files owner" "${defuser}" )"
+NETDATA_WEB_GROUP="$( config_option "web files group" "${NETDATA_WEB_USER}" )"
+
# debug flags
defdebug=0
NETDATA_DEBUG="$( config_option "debug flags" ${defdebug} )"
mkdir -p "${NETDATA_RUN_DIR}" || exit 1
fi
-echo >&2 "Fixing directory permissions for user ${NETDATA_USER}..."
+echo >&2 "Fixing directories (user: ${NETDATA_USER})..."
for x in "${NETDATA_WEB_DIR}" "${NETDATA_CONF_DIR}" "${NETDATA_CACHE_DIR}" "${NETDATA_LOG_DIR}"
do
if [ ! -d "${x}" ]
echo >&2 "Creating directory '${x}'"
run mkdir -p "${x}" || exit 1
fi
- run chown -R "${NETDATA_USER}:${NETDATA_USER}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_USER}..."
+
+ if [ ${UID} -eq 0 ]
+ then
+ if [ "${x}" = "${NETDATA_WEB_DIR}" ]
+ then
+ run chown -R "${NETDATA_WEB_USER}:${NETDATA_WEB_GROUP}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_WEB_USER}:${NETDATA_WEB_GROUP}..."
+ else
+ run chown -R "${NETDATA_USER}:${NETDATA_USER}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_USER}..."
+ fi
+ fi
+
run chmod 0775 "${x}" || echo >&2 "WARNING: Cannot change the permissions of the directory ${x} to 0755..."
done
-# fix apps.plugin to be setuid to root
-run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-run chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-
+if [ ${UID} -eq 0 ]
+ then
+ # fix apps.plugin to be setuid to root
+ run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+ run chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+fi
# -----------------------------------------------------------------------------
# check if we can re-start netdata
then
echo >&2 "Generating empty config file in: ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
echo "# Get config from http://127.0.0.1:${NETDATA_PORT}/netdata.conf" >"${NETDATA_PREFIX}/etc/netdata/netdata.conf"
- chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+
+ if [ "${UID}" -eq 0 ]
+ then
+ chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+ fi
chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
fi
echo >&2 "OK. It is now installed and ready."
mv "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
echo >&2 "New configuration saved for you to edit at ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
- chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+ if [ "${UID}" -eq 0 ]
+ then
+ chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+ fi
chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
else
echo >&2 "Cannnot download configuration from netdata daemon using url 'http://localhost:${NETDATA_PORT}/netdata.conf'"
fi
fi
-# -----------------------------------------------------------------------------
-
-cat <<END
-
-
--------------------------------------------------------------------------------
-
-ok. NetData is installed and is running.
-
-Hit http://localhost:${NETDATA_PORT}/ from your browser.
-
-To stop netdata, just kill it, with:
-
- killall netdata
-
-To start it, just run it:
-
- ${NETDATA_PREFIX}/usr/sbin/netdata
-
-Enjoy!
-
-END
-
# -----------------------------------------------------------------------------
# Check for KSM
ksm_is_available_but_disabled() {
cat <<KSM1
-INFORMATION:
+-------------------------------------------------------------------------------
+Memory de-duplication instructions
I see you have kernel memory de-duper (called Kernel Same-page Merging,
or KSM) available, but it is not currently enabled.
echo 1 >/sys/kernel/mm/ksm/run
echo 1000 >/sys/kernel/mm/ksm/sleep_millisecs
-If you enable it, you will save 20-60% of netdata memory.
+If you enable it, you will save 40-60% of netdata memory.
KSM1
}
ksm_is_not_available() {
cat <<KSM2
-INFORMATION:
+-------------------------------------------------------------------------------
+Memory de-duplication not present in your kernel
-I see you do not have kernel memory de-duper (called Kernel Same-page
+It seems you do not have kernel memory de-duper (called Kernel Same-page
Merging, or KSM) available.
To enable it, you need a kernel built with CONFIG_KSM=y
-If you can have it, you will save 20-60% of netdata memory.
+If you can have it, you will save 40-60% of netdata memory.
KSM2
}
then
cat <<VERMSG
-VERSION UPDATE CHECK:
+-------------------------------------------------------------------------------
+Version update check warning
-The way you downloaded netdata, we cannot find its version.
-This means the Update check on the dashboard, will not work.
+The way you downloaded netdata, we cannot find its version. This means the
+Update check on the dashboard, will not work.
If you want to have version update check, please re-install it
following the procedure in:
https://github.com/firehol/netdata/wiki/Installation
-
VERMSG
fi
+# -----------------------------------------------------------------------------
+# apps.plugin warning
+
+if [ "${UID}" -ne 0 ]
+ then
+cat <<SETUID_WARNING
+
+-------------------------------------------------------------------------------
+apps.plugin needs privileges
+
+Since you have installed netdata as a normal user, to have apps.plugin collect
+all the needed data, you have to give it the access rights it needs, by running
+these commands:
+
+ sudo chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+ sudo chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+
+The commands allow apps.plugin to run as root.
+
+apps.plugin is performing a hard-coded function of data collection for all
+running processes. It cannot be instructed from the netdata daemon to perform
+any task, so it is pretty safe to do this.
+
+SETUID_WARNING
+fi
+
# -----------------------------------------------------------------------------
# Keep un-install info
UNINSTALL
chmod 750 netdata-uninstaller.sh
+# -----------------------------------------------------------------------------
+
+cat <<END
+
+
+-------------------------------------------------------------------------------
+
+OK. NetData is installed and it is running.
+
+-------------------------------------------------------------------------------
+
+
+Hit http://localhost:${NETDATA_PORT}/ from your browser.
+
+To stop netdata, just kill it, with:
+
+ killall netdata
+
+To start it, just run it:
+
+ ${NETDATA_PREFIX}/usr/sbin/netdata
+
+
+Enjoy!
+
+ Give netdata a Github Star, at:
+
+ https://github.com/firehol/netdata/wiki
+
+
+END
echo >&2 "Uninstall script generated: ./netdata-uninstaller.sh"
+#
+# Conditional build:
+%bcond_without systemd # systemd
+%bcond_without nfacct # build with nfacct plugin
+
%if 0%{?fedora} || 0%{?rhel} >= 7
-%global do_systemd 1
%else
-%global do_systemd 0
+%undefine with_systemd
%endif
-Summary: Linux real time system monitoring, over the web
+Summary: Real-time performance monitoring, done right
Name: @PACKAGE_NAME@
Version: @PACKAGE_RPM_VERSION@
Release: @PACKAGE_RPM_RELEASE@%{?release_suffix}%{?dist}
-License: GPLv2+
-URL: http://firehol.org
-Source: %{name}-@PACKAGE_VERSION@.tar.bz2
-
-BuildRequires: libmnl-devel
+License: GPL v3+
+Group: Applications/System
+Source0: http://firehol.org/download/netdata/releases/v@PACKAGE_VERSION@/%{name}-@PACKAGE_VERSION@.tar.xz
+URL: http://netdata.firehol.org/
+BuildRequires: pkgconfig
+BuildRequires: xz
BuildRequires: zlib-devel
-Requires: libmnl
-Requires: zlib
-%if !0%{?rhel}
+%if %{with nfacct}
+BuildRequires: libmnl-devel
BuildRequires: libnetfilter_acct-devel
-Requires: libnetfilter_acct
%endif
-%if 0%{do_systemd}
+%if %{with systemd}
BuildRequires: systemd
Requires(post): systemd
Requires(preun): systemd
Requires(postun): systemd
%endif
-
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+BuildRoot: %{tmpdir}/%{name}-%{version}-root-%(id -u -n)
%description
-Real-time performance monitoring, in the greatest possible detail!
-
-%pre
-getent group netdata > /dev/null || groupadd -r netdata
-getent passwd netdata > /dev/null || useradd -r -g netdata -c netdata -s /sbin/nologin -d / netdata
-
-%if 0%{do_systemd}
-%post
-%systemd_post netdata.service
-%preun
-%systemd_preun netdata.service
-%postun
-%systemd_postun_with_restart netdata.service
-%endif
-
-%global ovirt_create_user_engine \
-%_ovirt_create_user %{engine_user} %{engine_uid} %{engine_group} %{engine_gid} "%{ovirt_user_description}" %{engine_state}
+netdata is the fastest way to visualize metrics. It is a resource
+efficient, highly optimized system for collecting and visualizing any
+type of realtime timeseries data, from CPU usage, disk activity, SQL
+queries, API calls, web site visitors, etc.
+netdata tries to visualize the truth of now, in its greatest detail,
+so that you can get insights of what is happening now and what just
+happened, on your systems and applications.
%prep
%setup -q -n %{name}-@PACKAGE_VERSION@
%build
%configure \
- --docdir="%{_docdir}/%{name}-%{version}" \
+ --docdir=%{_docdir}/%{name}-%{version} \
--with-zlib \
--with-math \
- --with-user=netdata \
-%if !0%{?rhel}
- --enable-plugin-nfacct \
-%endif
- %{?conf}
-make %{?_smp_mflags}
+ %{?with_nfacct:--enable-plugin-nfacct} \
+ --with-user=netdata
+%{__make} %{?_smp_mflags}
%install
-rm -rf "%{buildroot}"
-make %{?_smp_mflags} install DESTDIR="%{buildroot}"
-find "%{buildroot}" -name .keep -exec rm {} \;
+rm -rf $RPM_BUILD_ROOT
+%{__make} %{?_smp_mflags} install \
+ DESTDIR=$RPM_BUILD_ROOT
-%if 0%{do_systemd}
-install -m 0755 -d "%{buildroot}/%{_unitdir}"
-install -m 0644 system/netdata.service "%{buildroot}/%{_unitdir}"
+install -m 644 -p system/netdata.conf $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/*.conf
+
+find $RPM_BUILD_ROOT -name .keep | xargs rm
+
+%if %{with systemd}
+install -d $RPM_BUILD_ROOT%{_unitdir}
+install -m 644 -p system/netdata.service $RPM_BUILD_ROOT%{_unitdir}/netdata.service
+%endif
+
+%pre
+getent group netdata > /dev/null || groupadd -r netdata
+getent passwd netdata > /dev/null || useradd -r -g netdata -c netdata -s /sbin/nologin -d / netdata
+
+%if %{with systemd}
+%post
+%systemd_post netdata.service
+
+%preun
+%systemd_preun netdata.service
+
+%postun
+%systemd_postun_with_restart netdata.service
%endif
+%clean
+rm -rf $RPM_BUILD_ROOT
+
%files
-%attr(-, netdata, netdata) %dir %{_localstatedir}/cache/%{name}/
-%attr(-, netdata, netdata) %dir %{_localstatedir}/log/%{name}/
-%config(noreplace) %{_sysconfdir}/%{name}/
-%{_datadir}/%{name}/
-%{_libexecdir}/%{name}/
+%attr(-,netdata,netdata) %dir %{_localstatedir}/cache/%{name}
+%attr(-,netdata,netdata) %dir %{_localstatedir}/log/%{name}
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/%{name}/*.conf
+%dir %{_sysconfdir}/%{name}
+%{?with_systemd:%{_unitdir}/netdata.service}
+%{_libexecdir}/%{name}
%{_sbindir}/%{name}
+%dir %{_datadir}/%{name}
-%if 0%{do_systemd}
-%{_unitdir}/netdata.service
-%endif
+# override defattr for web files
+%defattr(755,root,netdata,644)
+%{_datadir}/%{name}/web
%changelog
+* Wed Apr 20 2016 Costa Tsaousis <costa@tsaousis.gr> - 1.1.0-1
+- Several new features (IPv6, SYNPROXY, Users, Users Groups).
+- A lot of bug fixes and optimizations.
* Tue Mar 22 2016 Costa Tsaousis <costa@tsaousis.gr> - 1.0.0-1
- First public release.
* Sun Nov 15 2015 Alon Bar-Lev <alonbl@redhat.com> - 0.0.0-1
-e '/: unittest$/d' \
-e '/: iprange$/d' \
-e '/: .*\.o$/d' \
+ -e '/: CMakeLists.txt/d' \
+ -e '/: .travis.yml/d' \
-e '/sbin: \(firehol\|fireqos\|link-balancer\)$/d' \
-e '/sbin: \(update-ipsets\|vnetbuild\|commands.sed\)$/d' > $MYTMP/out
#!/bin/bash
+export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin"
+
# default time function
now_ms=
current_time_ms() {
#include "common.h"
#include "log.h"
#include "procfile.h"
+#include "../config.h"
-#define MAX_COMPARE_NAME 15
+#define MAX_COMPARE_NAME 100
#define MAX_NAME 100
+#define MAX_CMDLINE 1024
unsigned long long Hertz = 1;
int update_every = 1;
unsigned long long file_counter = 0;
+int proc_pid_cmdline_is_needed = 0;
char *host_prefix = "";
char *config_dir = CONFIG_DIR;
#endif /* NETDATA_INTERNAL_CHECKS */
-
// ----------------------------------------------------------------------------
// system functions
// to retrieve settings of the system
-procfile *ff = NULL;
-
long get_system_cpus(void) {
+ procfile *ff = NULL;
+
int processors = 0;
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
- ff = procfile_reopen(ff, filename, "", PROCFILE_FLAG_DEFAULT);
+ ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
if(!ff) return 1;
ff = procfile_readall(ff);
if(!ff) {
- // procfile_close(ff);
+ procfile_close(ff);
return 1;
}
processors--;
if(processors < 1) processors = 1;
- // procfile_close(ff);
+ procfile_close(ff);
return processors;
}
long get_system_pid_max(void) {
+ procfile *ff = NULL;
long mpid = 32768;
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", host_prefix);
- ff = procfile_reopen(ff, filename, "", PROCFILE_FLAG_DEFAULT);
+ ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
if(!ff) return mpid;
ff = procfile_readall(ff);
if(!ff) {
- // procfile_close(ff);
+ procfile_close(ff);
return mpid;
}
mpid = atol(procfile_lineword(ff, 0, 0));
if(!mpid) mpid = 32768;
- // procfile_close(ff);
+ procfile_close(ff);
return mpid;
}
struct target {
char compare[MAX_COMPARE_NAME + 1];
- uint32_t hash;
+ uint32_t comparehash;
+ size_t comparelen;
char id[MAX_NAME + 1];
+ uint32_t idhash;
+
char name[MAX_NAME + 1];
uid_t uid;
int exposed; // if set, we have sent this to netdata
int hidden; // if set, we set the hidden flag on the dimension
int debug;
+ int ends_with;
+ int starts_with; // if set, the compare string matches only the
+ // beginning of the command
struct target *target; // the one that will be reported to netdata
struct target *next;
}
snprintf(w->compare, MAX_COMPARE_NAME, "%d", uid);
- w->hash = simple_hash(w->compare);
+ w->comparehash = simple_hash(w->compare);
+ w->comparelen = strlen(w->compare);
snprintf(w->id, MAX_NAME, "%d", uid);
+ w->idhash = simple_hash(w->id);
struct passwd *pw = getpwuid(uid);
if(!pw)
else
snprintf(w->name, MAX_NAME, "%s", pw->pw_name);
+ netdata_fix_id(w->name);
+
w->uid = uid;
w->next = users_root_target;
}
snprintf(w->compare, MAX_COMPARE_NAME, "%d", gid);
- w->hash = simple_hash(w->compare);
+ w->comparehash = simple_hash(w->compare);
+ w->comparelen = strlen(w->compare);
snprintf(w->id, MAX_NAME, "%d", gid);
+ w->idhash = simple_hash(w->id);
struct group *gr = getgrgid(gid);
if(!gr)
else
snprintf(w->name, MAX_NAME, "%s", gr->gr_name);
+ netdata_fix_id(w->name);
+
w->gid = gid;
w->next = groups_root_target;
// there are targets that are just aggregated to other target (the second argument)
struct target *get_apps_groups_target(const char *id, struct target *target)
{
+ int tdebug = 0, thidden = 0, ends_with = 0;
const char *nid = id;
- if(nid[0] == '-') nid++;
+
+ while(nid[0] == '-' || nid[0] == '+' || nid[0] == '*') {
+ if(nid[0] == '-') thidden = 1;
+ if(nid[0] == '+') tdebug = 1;
+ if(nid[0] == '*') ends_with = 1;
+ nid++;
+ }
+ uint32_t hash = simple_hash(id);
struct target *w;
- for(w = apps_groups_root_target ; w ; w = w->next)
- if(strncmp(nid, w->id, MAX_NAME) == 0) return w;
+ for(w = apps_groups_root_target ; w ; w = w->next) {
+ if(w->idhash == hash && strncmp(nid, w->id, MAX_NAME) == 0)
+ return w;
+ }
w = calloc(sizeof(struct target), 1);
if(unlikely(!w)) {
}
strncpy(w->id, nid, MAX_NAME);
+ w->idhash = simple_hash(w->id);
+
strncpy(w->name, nid, MAX_NAME);
+
strncpy(w->compare, nid, MAX_COMPARE_NAME);
- w->hash = simple_hash(w->compare);
+ int len = strlen(w->compare);
+ if(w->compare[len - 1] == '*') {
+ w->compare[len - 1] = '\0';
+ w->starts_with = 1;
+ }
+ w->ends_with = ends_with;
- if(id[0] == '-') w->hidden = 1;
+ if(w->starts_with && w->ends_with)
+ proc_pid_cmdline_is_needed = 1;
+ w->comparehash = simple_hash(w->compare);
+ w->comparelen = strlen(w->compare);
+
+ w->hidden = thidden;
+ w->debug = tdebug;
w->target = target;
w->next = apps_groups_root_target;
apps_groups_root_target = w;
if(unlikely(debug))
- fprintf(stderr, "apps.plugin: adding hook for process '%s', compare '%s' on target '%s'\n", w->id, w->compare, w->target?w->target->id:"");
+ fprintf(stderr, "apps.plugin: ADDING TARGET ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
+ , w->id
+ , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
+ , w->target?w->target->id:w->id
+ , (w->hidden)?"hidden":"-"
+ , (w->debug)?"debug":"-"
+ );
return w;
}
// read the apps_groups.conf file
int read_apps_groups_conf(const char *name)
{
- char buffer[4096+1];
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, name);
if(unlikely(debug))
fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
- FILE *fp = fopen(filename, "r");
- if(unlikely(!fp)) {
- error("Cannot open file '%s'", filename);
- return 1;
- }
+ // ----------------------------------------
- long line = 0;
- while(fgets(buffer, 4096, fp) != NULL) {
- int whidden = 0, wdebug = 0;
- line++;
+ procfile *ff = procfile_open(filename, " :\t", PROCFILE_FLAG_DEFAULT);
+ if(!ff) return 1;
- // if(debug) fprintf(stderr, "apps.plugin: \tread %s\n", buffer);
+ procfile_set_quotes(ff, "'\"");
+
+ ff = procfile_readall(ff);
+ if(!ff) {
+ procfile_close(ff);
+ return 1;
+ }
- char *s = buffer, *t, *p;
- s = trim(s);
- if(!s || !*s || *s == '#') continue;
+ unsigned long line, lines = procfile_lines(ff);
- if(debug) fprintf(stderr, "apps.plugin: \tread %s\n", s);
+ for(line = 0; line < lines ;line++) {
+ unsigned long word, words = procfile_linewords(ff, line);
+ struct target *w = NULL;
- // the target name
- t = strsep(&s, ":");
- if(t) t = trim(t);
+ char *t = procfile_lineword(ff, line, 0);
if(!t || !*t) continue;
- while(t[0]) {
- int stop = 1;
+ for(word = 0; word < words ;word++) {
+ char *s = procfile_lineword(ff, line, word);
+ if(!s || !*s) continue;
+ if(*s == '#') break;
- switch(t[0]) {
- case '-':
- stop = 0;
- whidden = 1;
- t++;
- break;
+ if(t == s) continue;
- case '+':
- stop = 0;
- wdebug = 1;
- t++;
- break;
+ struct target *n = get_apps_groups_target(s, w);
+ if(!n) {
+ error("Cannot create target '%s' (line %d, word %d)", s, line, word);
+ continue;
}
- if(stop) break;
+ if(!w) w = n;
}
- if(debug) fprintf(stderr, "apps.plugin: \t\ttarget %s\n", t);
-
- struct target *w = NULL;
- long count = 0;
- int blen = 0;
- char buffer[4097] = "";
- buffer[4096] = '\0';
-
- // the process names
- while((p = strsep(&s, " "))) {
- p = trim(p);
- if(!p || !*p) continue;
-
- strncpy(&buffer[blen], p, 4096 - blen);
- blen = strlen(buffer);
-
- while(buffer[blen - 1] == '\\') {
- buffer[blen - 1] = ' ';
-
- if((p = strsep(&s, " ")))
- p = trim(p);
+ if(w) {
+ int tdebug = 0, thidden = 0;
- if(!p || !*p) p = " ";
- strncpy(&buffer[blen], p, 4096 - blen);
- blen = strlen(buffer);
+ while(t[0] == '-' || t[0] == '+') {
+ if(t[0] == '-') thidden = 1;
+ if(t[0] == '+') tdebug = 1;
+ t++;
}
- struct target *n = get_apps_groups_target(buffer, w);
- n->hidden = whidden;
- n->debug = wdebug;
- if(!w) w = n;
-
- buffer[0] = '\0';
- blen = 0;
-
- count++;
+ strncpy(w->name, t, MAX_NAME);
+ w->name[MAX_NAME] = '\0';
+ w->hidden = thidden;
+ w->debug = tdebug;
+
+ if(unlikely(debug))
+ fprintf(stderr, "apps.plugin: AGGREGATION TARGET NAME '%s' on ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
+ , w->name
+ , w->id
+ , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
+ , w->target?w->target->id:w->id
+ , (w->hidden)?"hidden":"-"
+ , (w->debug)?"debug":"-"
+ );
}
-
- if(w) strncpy(w->name, t, MAX_NAME);
- if(!count) error("The line %ld on file '%s', for group '%s' does not state any process names.", line, filename, t);
}
- fclose(fp);
- apps_groups_default_target = get_apps_groups_target("+p!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing
- strncpy(apps_groups_default_target->name, "other", MAX_NAME);
+ procfile_close(ff);
+
+ apps_groups_default_target = get_apps_groups_target("p+!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing
+ if(!apps_groups_default_target)
+ error("Cannot create default target");
+ else
+ strncpy(apps_groups_default_target->name, "other", MAX_NAME);
return 0;
}
struct pid_stat {
int32_t pid;
char comm[MAX_COMPARE_NAME + 1];
+ char cmdline[MAX_CMDLINE + 1];
+
// char state;
int32_t ppid;
// int32_t pgrp;
// ----------------------------------------------------------------------------
// update pids from proc
+int read_proc_pid_cmdline(struct pid_stat *p) {
+ char filename[FILENAME_MAX + 1];
+ snprintf(filename, FILENAME_MAX, "%s/proc/%d/cmdline", host_prefix, p->pid);
+
+ int fd = open(filename, O_RDONLY, 0666);
+ if(unlikely(fd == -1)) return 1;
+
+ int i, bytes = read(fd, p->cmdline, MAX_CMDLINE);
+ close(fd);
+
+ if(bytes <= 0) {
+ // copy the command to the command line
+ strncpy(p->cmdline, p->comm, MAX_CMDLINE);
+ p->cmdline[MAX_CMDLINE] = '\0';
+ return 0;
+ }
+
+ p->cmdline[bytes] = '\0';
+ for(i = 0; i < bytes ; i++)
+ if(!p->cmdline[i]) p->cmdline[i] = ' ';
+
+ if(unlikely(debug))
+ fprintf(stderr, "Read file '%s' contents: %s\n", filename, p->cmdline);
+
+ return 0;
+}
+
int read_proc_pid_ownership(struct pid_stat *p) {
char filename[FILENAME_MAX + 1];
}
int read_proc_pid_stat(struct pid_stat *p) {
+ static procfile *ff = NULL;
+
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
// ----------------------------------------
+ int set_quotes = (!ff)?1:0;
+
ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
if(!ff) return 1;
+ // if(set_quotes) procfile_set_quotes(ff, "()");
+ if(set_quotes) procfile_set_open_close(ff, "(", ")");
+
ff = procfile_readall(ff);
if(!ff) {
// procfile_close(ff);
file_counter++;
- p->comm[0] = '\0';
- p->comm[MAX_COMPARE_NAME] = '\0';
- size_t blen = 0;
-
- char *s = procfile_lineword(ff, 0, 1);
- if(*s == '(') s++;
- size_t len = strlen(s);
+ // parse the process name
unsigned int i = 0;
- while(len && s[len - 1] != ')') {
- if(blen < MAX_COMPARE_NAME) {
- strncpy(&p->comm[blen], s, MAX_COMPARE_NAME - blen);
- blen = strlen(p->comm);
- }
-
- i++;
- s = procfile_lineword(ff, 0, 1+i);
- len = strlen(s);
- }
- if(len && s[len - 1] == ')') s[len - 1] = '\0';
- if(blen < MAX_COMPARE_NAME)
- strncpy(&p->comm[blen], s, MAX_COMPARE_NAME - blen);
+ strncpy(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
+ p->comm[MAX_COMPARE_NAME] = '\0';
// p->pid = atol(procfile_lineword(ff, 0, 0+i));
// comm is at 1
// p->guest_time = strtoull(procfile_lineword(ff, 0, 42+i), NULL, 10);
// p->cguest_time = strtoull(procfile_lineword(ff, 0, 43), NULL, 10);
- if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: VALUES: %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", p->comm, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
+ if(debug || (p->target && p->target->debug))
+ fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", host_prefix, p->pid, p->comm, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
// procfile_close(ff);
return 0;
}
int read_proc_pid_statm(struct pid_stat *p) {
+ static procfile *ff = NULL;
+
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s/proc/%d/statm", host_prefix, p->pid);
}
int read_proc_pid_io(struct pid_stat *p) {
+ static procfile *ff = NULL;
+
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s/proc/%d/io", host_prefix, p->pid);
int collect_data_for_all_processes_from_proc(void)
{
- static long count_errors = 0;
-
char dirname[FILENAME_MAX + 1];
snprintf(dirname, FILENAME_MAX, "%s/proc", host_prefix);
// /proc/<pid>/stat
if(unlikely(read_proc_pid_stat(p))) {
- if(!count_errors++ || debug || (p->target && p->target->debug))
error("Cannot process %s/proc/%d/stat", host_prefix, pid);
// there is no reason to proceed if we cannot get its status
// check its parent pid
if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
- if(unlikely(!count_errors++ || debug || (p->target && p->target->debug)))
error("Pid %d states invalid parent pid %d. Using 0.", pid, p->ppid);
p->ppid = 0;
}
+ // --------------------------------------------------------------------
+ // /proc/<pid>/cmdline
+
+ if(proc_pid_cmdline_is_needed) {
+ if(unlikely(read_proc_pid_cmdline(p))) {
+ error("Cannot process %s/proc/%d/cmdline", host_prefix, pid);
+ }
+ }
// --------------------------------------------------------------------
// /proc/<pid>/statm
if(unlikely(read_proc_pid_statm(p))) {
- if(unlikely(!count_errors++ || debug || (p->target && p->target->debug)))
error("Cannot process %s/proc/%d/statm", host_prefix, pid);
// there is no reason to proceed if we cannot get its memory status
// /proc/<pid>/io
if(unlikely(read_proc_pid_io(p))) {
- if(unlikely(!count_errors++ || debug || (p->target && p->target->debug)))
error("Cannot process %s/proc/%d/io", host_prefix, pid);
// on systems without /proc/X/io
// <pid> ownership
if(unlikely(read_proc_pid_ownership(p))) {
- if(unlikely(!count_errors++ || debug || (p->target && p->target->debug)))
error("Cannot stat %s/proc/%d", host_prefix, pid);
}
if(unlikely(p->new_entry)) {
if(debug) fprintf(stderr, "apps.plugin: \tJust added %s\n", p->comm);
uint32_t hash = simple_hash(p->comm);
+ size_t pclen = strlen(p->comm);
struct target *w;
for(w = apps_groups_root_target; w ; w = w->next) {
// if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
- if(w->hash == hash && strcmp(w->compare, p->comm) == 0) {
+ // find it - 4 cases:
+ // 1. the target is not a pattern
+ // 2. the target has the prefix
+ // 3. the target has the suffix
+ // 4. the target is something inside cmdline
+ if( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
+ || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
+ || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
+ || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
+ ) {
if(w->target) p->target = w->target;
else p->target = w;
// /proc/<pid>/fd
if(unlikely(read_pid_file_descriptors(p))) {
- if(unlikely(!count_errors++ || debug || (p->target && p->target->debug)))
error("Cannot process entries in %s/proc/%d/fd", host_prefix, pid);
}
p->updated = 1;
}
- if(unlikely(count_errors > 1000)) {
- error("%ld more errors encountered\n", count_errors - 1);
- count_errors = 0;
- }
-
closedir(dir);
return 1;
// set the name for logging
program_name = "apps.plugin";
+ // disable syslog for apps.plugin
+ error_log_syslog = 0;
+
host_prefix = getenv("NETDATA_HOST_PREFIX");
if(host_prefix == NULL) {
info("NETDATA_HOST_PREFIX is not passed from netdata");
#include "log.h"
#include "common.h"
#include "appconfig.h"
+#include "../config.h"
char *global_host_prefix = "";
int enable_ksm = 1;
+unsigned char netdata_keys_map[256] = {
+ [0] = '\0', //
+ [1] = '_', //
+ [2] = '_', //
+ [3] = '_', //
+ [4] = '_', //
+ [5] = '_', //
+ [6] = '_', //
+ [7] = '_', //
+ [8] = '_', //
+ [9] = '_', //
+ [10] = '_', //
+ [11] = '_', //
+ [12] = '_', //
+ [13] = '_', //
+ [14] = '_', //
+ [15] = '_', //
+ [16] = '_', //
+ [17] = '_', //
+ [18] = '_', //
+ [19] = '_', //
+ [20] = '_', //
+ [21] = '_', //
+ [22] = '_', //
+ [23] = '_', //
+ [24] = '_', //
+ [25] = '_', //
+ [26] = '_', //
+ [27] = '_', //
+ [28] = '_', //
+ [29] = '_', //
+ [30] = '_', //
+ [31] = '_', //
+ [32] = '_', //
+ [33] = '_', // !
+ [34] = '_', // "
+ [35] = '_', // #
+ [36] = '_', // $
+ [37] = '_', // %
+ [38] = '_', // &
+ [39] = '_', // '
+ [40] = '_', // (
+ [41] = '_', // )
+ [42] = '_', // *
+ [43] = '_', // +
+ [44] = '.', // ,
+ [45] = '-', // -
+ [46] = '.', // .
+ [47] = '/', // /
+ [48] = '0', // 0
+ [49] = '1', // 1
+ [50] = '2', // 2
+ [51] = '3', // 3
+ [52] = '4', // 4
+ [53] = '5', // 5
+ [54] = '6', // 6
+ [55] = '7', // 7
+ [56] = '8', // 8
+ [57] = '9', // 9
+ [58] = '_', // :
+ [59] = '_', // ;
+ [60] = '_', // <
+ [61] = '_', // =
+ [62] = '_', // >
+ [63] = '_', // ?
+ [64] = '_', // @
+ [65] = 'a', // A
+ [66] = 'b', // B
+ [67] = 'c', // C
+ [68] = 'd', // D
+ [69] = 'e', // E
+ [70] = 'f', // F
+ [71] = 'g', // G
+ [72] = 'h', // H
+ [73] = 'i', // I
+ [74] = 'j', // J
+ [75] = 'k', // K
+ [76] = 'l', // L
+ [77] = 'm', // M
+ [78] = 'n', // N
+ [79] = 'o', // O
+ [80] = 'p', // P
+ [81] = 'q', // Q
+ [82] = 'r', // R
+ [83] = 's', // S
+ [84] = 't', // T
+ [85] = 'u', // U
+ [86] = 'v', // V
+ [87] = 'w', // W
+ [88] = 'x', // X
+ [89] = 'y', // Y
+ [90] = 'z', // Z
+ [91] = '_', // [
+ [92] = '/', // backslash
+ [93] = '_', // ]
+ [94] = '_', // ^
+ [95] = '_', // _
+ [96] = '_', // `
+ [97] = 'a', // a
+ [98] = 'b', // b
+ [99] = 'c', // c
+ [100] = 'd', // d
+ [101] = 'e', // e
+ [102] = 'f', // f
+ [103] = 'g', // g
+ [104] = 'h', // h
+ [105] = 'i', // i
+ [106] = 'j', // j
+ [107] = 'k', // k
+ [108] = 'l', // l
+ [109] = 'm', // m
+ [110] = 'n', // n
+ [111] = 'o', // o
+ [112] = 'p', // p
+ [113] = 'q', // q
+ [114] = 'r', // r
+ [115] = 's', // s
+ [116] = 't', // t
+ [117] = 'u', // u
+ [118] = 'v', // v
+ [119] = 'w', // w
+ [120] = 'x', // x
+ [121] = 'y', // y
+ [122] = 'z', // z
+ [123] = '_', // {
+ [124] = '_', // |
+ [125] = '_', // }
+ [126] = '_', // ~
+ [127] = '_', //
+ [128] = '_', //
+ [129] = '_', //
+ [130] = '_', //
+ [131] = '_', //
+ [132] = '_', //
+ [133] = '_', //
+ [134] = '_', //
+ [135] = '_', //
+ [136] = '_', //
+ [137] = '_', //
+ [138] = '_', //
+ [139] = '_', //
+ [140] = '_', //
+ [141] = '_', //
+ [142] = '_', //
+ [143] = '_', //
+ [144] = '_', //
+ [145] = '_', //
+ [146] = '_', //
+ [147] = '_', //
+ [148] = '_', //
+ [149] = '_', //
+ [150] = '_', //
+ [151] = '_', //
+ [152] = '_', //
+ [153] = '_', //
+ [154] = '_', //
+ [155] = '_', //
+ [156] = '_', //
+ [157] = '_', //
+ [158] = '_', //
+ [159] = '_', //
+ [160] = '_', //
+ [161] = '_', //
+ [162] = '_', //
+ [163] = '_', //
+ [164] = '_', //
+ [165] = '_', //
+ [166] = '_', //
+ [167] = '_', //
+ [168] = '_', //
+ [169] = '_', //
+ [170] = '_', //
+ [171] = '_', //
+ [172] = '_', //
+ [173] = '_', //
+ [174] = '_', //
+ [175] = '_', //
+ [176] = '_', //
+ [177] = '_', //
+ [178] = '_', //
+ [179] = '_', //
+ [180] = '_', //
+ [181] = '_', //
+ [182] = '_', //
+ [183] = '_', //
+ [184] = '_', //
+ [185] = '_', //
+ [186] = '_', //
+ [187] = '_', //
+ [188] = '_', //
+ [189] = '_', //
+ [190] = '_', //
+ [191] = '_', //
+ [192] = '_', //
+ [193] = '_', //
+ [194] = '_', //
+ [195] = '_', //
+ [196] = '_', //
+ [197] = '_', //
+ [198] = '_', //
+ [199] = '_', //
+ [200] = '_', //
+ [201] = '_', //
+ [202] = '_', //
+ [203] = '_', //
+ [204] = '_', //
+ [205] = '_', //
+ [206] = '_', //
+ [207] = '_', //
+ [208] = '_', //
+ [209] = '_', //
+ [210] = '_', //
+ [211] = '_', //
+ [212] = '_', //
+ [213] = '_', //
+ [214] = '_', //
+ [215] = '_', //
+ [216] = '_', //
+ [217] = '_', //
+ [218] = '_', //
+ [219] = '_', //
+ [220] = '_', //
+ [221] = '_', //
+ [222] = '_', //
+ [223] = '_', //
+ [224] = '_', //
+ [225] = '_', //
+ [226] = '_', //
+ [227] = '_', //
+ [228] = '_', //
+ [229] = '_', //
+ [230] = '_', //
+ [231] = '_', //
+ [232] = '_', //
+ [233] = '_', //
+ [234] = '_', //
+ [235] = '_', //
+ [236] = '_', //
+ [237] = '_', //
+ [238] = '_', //
+ [239] = '_', //
+ [240] = '_', //
+ [241] = '_', //
+ [242] = '_', //
+ [243] = '_', //
+ [244] = '_', //
+ [245] = '_', //
+ [246] = '_', //
+ [247] = '_', //
+ [248] = '_', //
+ [249] = '_', //
+ [250] = '_', //
+ [251] = '_', //
+ [252] = '_', //
+ [253] = '_', //
+ [254] = '_', //
+ [255] = '_' //
+};
+
+// make sure the supplied string
+// is good for a netdata chart/dimension ID/NAME
+void netdata_fix_id(char *s) {
+ while((*s = netdata_keys_map[(unsigned char)*s])) s++;
+}
+
/*
// http://stackoverflow.com/questions/7666509/hash-function-for-string
uint32_t simple_hash(const char *name)
#define abs(x) ((x < 0)? -x : x)
#define usecdiff(now, last) (((((now)->tv_sec * 1000000ULL) + (now)->tv_usec) - (((last)->tv_sec * 1000000ULL) + (last)->tv_usec)))
+extern void netdata_fix_id(char *s);
+
extern uint32_t simple_hash(const char *name);
extern void strreverse(char* begin, char* end);
extern char *mystrsep(char **ptr, char *s);
return -1;
}
- if(pidfile[0] && getuid() != pw->pw_uid) {
+ uid_t uid = pw->pw_uid;
+ gid_t gid = pw->pw_gid;
+
+ if(pidfile[0] && getuid() != uid) {
// we are dropping privileges
- if(chown(pidfile, pw->pw_uid, pw->pw_gid) != 0)
+ if(chown(pidfile, uid, gid) != 0)
error("Cannot chown pidfile '%s' to user '%s'", pidfile, username);
else if(pidfd != -1) {
pidfd = -1;
}
- if(setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
- error("Cannot switch to user's %s group (gid: %d).", username, pw->pw_gid);
+ if(setresgid(gid, gid, gid) != 0) {
+ error("Cannot switch to user's %s group (gid: %d).", username, gid);
return -1;
}
- if(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
- error("Cannot switch to user %s (uid: %d).", username, pw->pw_uid);
+ if(setresuid(uid, uid, uid) != 0) {
+ error("Cannot switch to user %s (uid: %d).", username, uid);
return -1;
}
- if(setgid(pw->pw_gid) != 0) {
- error("Cannot switch to user's %s group (gid: %d).", username, pw->pw_gid);
+ if(setgid(gid) != 0) {
+ error("Cannot switch to user's %s group (gid: %d).", username, gid);
return -1;
}
- if(setegid(pw->pw_gid) != 0) {
- error("Cannot effectively switch to user's %s group (gid: %d).", username, pw->pw_gid);
+ if(setegid(gid) != 0) {
+ error("Cannot effectively switch to user's %s group (gid: %d).", username, gid);
return -1;
}
- if(setuid(pw->pw_uid) != 0) {
- error("Cannot switch to user %s (uid: %d).", username, pw->pw_uid);
+ if(setuid(uid) != 0) {
+ error("Cannot switch to user %s (uid: %d).", username, uid);
return -1;
}
- if(seteuid(pw->pw_uid) != 0) {
- error("Cannot effectively switch to user %s (uid: %d).", username, pw->pw_uid);
+ if(seteuid(uid) != 0) {
+ error("Cannot effectively switch to user %s (uid: %d).", username, uid);
return -1;
}
int error_log_syslog = 1;
int output_log_syslog = 1; // debug log
+time_t error_log_throttle_period = 1200;
+unsigned long error_log_errors_per_period = 200;
+
+int error_log_limit(int reset) {
+ static time_t start = 0;
+ static unsigned long counter = 0, prevented = 0;
+
+ // do not throttle if the period is 0
+ if(error_log_throttle_period == 0)
+ return 0;
+
+ // prevent all logs if the errors per period is 0
+ if(error_log_errors_per_period == 0)
+ return 1;
+
+ time_t now = time(NULL);
+ if(!start) start = now;
+
+ if(reset) {
+ if(prevented) {
+ log_date(stderr);
+ fprintf(stderr, "%s: Resetting logging for process '%s' (prevented %lu logs in the last %ld seconds).\n"
+ , program_name
+ , program_name
+ , prevented
+ , now - start
+ );
+ }
+
+ start = now;
+ counter = 0;
+ prevented = 0;
+ }
+
+ // detect if we log too much
+ counter++;
+
+ if(now - start > error_log_throttle_period) {
+ if(prevented) {
+ log_date(stderr);
+ fprintf(stderr, "%s: Resuming logging from process '%s' (prevented %lu logs in the last %ld seconds).\n"
+ , program_name
+ , program_name
+ , prevented
+ , error_log_throttle_period
+ );
+ }
+
+ // restart the period accounting
+ start = now;
+ counter = 1;
+ prevented = 0;
+
+ // log this error
+ return 0;
+ }
+
+ if(counter > error_log_errors_per_period) {
+ if(!prevented) {
+ log_date(stderr);
+ fprintf(stderr, "%s: Too many logs (%lu logs in %ld seconds, threshold is set to %lu logs in %ld seconds). Preventing more logs from process '%s' for %ld seconds.\n"
+ , program_name
+ , counter
+ , now - start
+ , error_log_errors_per_period
+ , error_log_throttle_period
+ , program_name
+ , start + error_log_throttle_period - now);
+ }
+
+ prevented++;
+
+ // prevent logging this error
+ return 1;
+ }
+
+ return 0;
+}
+
void log_date(FILE *out)
{
char outstr[200];
{
va_list args;
+ // prevent logging too much
+ if(error_log_limit(0)) return;
+
log_date(stderr);
va_start( args, fmt );
{
va_list args;
+ // prevent logging too much
+ if(error_log_limit(0)) return;
+
log_date(stderr);
va_start( args, fmt );
extern int error_log_syslog;
extern int output_log_syslog;
+extern time_t error_log_throttle_period;
+extern unsigned long error_log_errors_per_period;
+extern int error_log_limit(int reset);
+
+#define error_log_limit_reset() do { error_log_limit(1); } while(0)
+
#define debug(type, args...) do { if(unlikely(!silent && (debug_flags & type))) debug_int(__FILE__, __FUNCTION__, __LINE__, ##args); } while(0)
#define info(args...) info_int(__FILE__, __FUNCTION__, __LINE__, ##args)
#define infoerr(args...) error_int("INFO", __FILE__, __FUNCTION__, __LINE__, ##args)
#include "plugin_nfacct.h"
#include "main.h"
+#include "../config.h"
int netdata_exit = 0;
rrdset_save_all();
// kill_childs();
+ // let it log a few more error messages
+ error_log_limit_reset();
+
if(pidfd != -1) {
if(ftruncate(pidfd, 0) != 0)
error("Cannot truncate pidfile '%s'.", pidfile);
}
else error_log_syslog = 0;
+ error_log_throttle_period = config_get_number("global", "errors flood protection period", error_log_throttle_period);
+ setenv("NETDATA_ERRORS_THROTTLE_PERIOD", config_get("global", "errors flood protection period" , ""), 1);
+
+ error_log_errors_per_period = config_get_number("global", "errors to trigger flood protection", error_log_errors_per_period);
+ setenv("NETDATA_ERRORS_PER_PERIOD" , config_get("global", "errors to trigger flood protection", ""), 1);
+
// --------------------------------------------------------------------
access_log_file = config_get("global", "access log", LOG_DIR "/access.log");
// --------------------------------------------------------------------
+ // get the user we should run
+ // IMPORTANT: this is required before web_files_uid()
user = config_get("global", "run as user" , (getuid() == 0)?NETDATA_USER:"");
- web_files_uid();
+
+ // IMPORTANT: these have to run once, while single threaded
+ web_files_uid(); // IMPORTANT: web_files_uid() before web_files_gid()
+ web_files_gid();
// --------------------------------------------------------------------
#include "popen.h"
#include "plugin_tc.h"
#include "main.h"
+#include "../config.h"
#define RRD_TYPE_TC "tc"
#define RRD_TYPE_TC_LEN strlen(RRD_TYPE_TC)
// debug(D_TC_LOOP, "IGNORED line");
//}
}
- mypclose(fp, tc_child_pid);
+ // fgets() failed or loop broke
+ int code = mypclose(fp, tc_child_pid);
tc_child_pid = 0;
if(device) {
return NULL;
}
+ if(code == 1 || code == 127) {
+ // 1 = DISABLE
+ // 127 = cannot even run it
+ error("TC: tc-qos-helper.sh exited with code %d. Disabling it.", code);
+
+ tc_device_free_all();
+ pthread_exit(NULL);
+ return NULL;
+ }
+
sleep((unsigned int) rrd_update_every);
}
pthread_exit(NULL);
return NULL;
}
-
#include "rrd.h"
#include "popen.h"
#include "plugins_d.h"
+#include "../config.h"
struct plugind *pluginsd_root = NULL;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include "common.h"
#include "log.h"
#define RRD_TYPE_DISK "disk"
+struct disk {
+ unsigned long major;
+ unsigned long minor;
+ int partition_id; // -1 = this is not a partition
+ struct disk *next;
+} *disk_root = NULL;
+
+struct disk *get_disk(unsigned long major, unsigned long minor) {
+ static char path_find_block_device_partition[FILENAME_MAX + 1] = "";
+ struct disk *d;
+
+ // search for it in our RAM list.
+ // this is sequential, but since we just walk through
+ // and the number of disks / partitions in a system
+ // should not be that many, it should be acceptable
+ for(d = disk_root; d ; d = d->next)
+ if(unlikely(d->major == major && d->minor == minor))
+ break;
+
+ // if we found it, return it
+ if(likely(d))
+ return d;
+
+ if(unlikely(!path_find_block_device_partition[0])) {
+ char filename[FILENAME_MAX + 1];
+ snprintf(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/partition");
+ snprintf(path_find_block_device_partition, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device partition", filename));
+ }
+
+ // not found
+ // create a new disk structure
+ d = (struct disk *)malloc(sizeof(struct disk));
+ if(!d) fatal("Cannot allocate memory for struct disk in proc_diskstats.");
+
+ d->major = major;
+ d->minor = minor;
+ d->partition_id = -1;
+ d->next = NULL;
+
+ // append it to the list
+ if(!disk_root)
+ disk_root = d;
+ else {
+ struct disk *last;
+ for(last = disk_root; last->next ;last = last->next);
+ last->next = d;
+ }
+
+ // find if it is a partition
+ // by reading /sys/dev/block/MAJOR:MINOR/partition
+ char buffer[FILENAME_MAX + 1];
+ snprintf(buffer, FILENAME_MAX, path_find_block_device_partition, major, minor);
+
+ int fd = open(buffer, O_RDONLY, 0666);
+ if(likely(fd != -1)) {
+ // we opened it
+ int bytes = read(fd, buffer, FILENAME_MAX);
+ close(fd);
+
+ if(bytes > 0)
+ d->partition_id = strtoul(buffer, NULL, 10);
+ }
+ // if the /partition file does not exist, it is a disk, not a partition
+
+ return d;
+}
+
int do_proc_diskstats(int update_every, unsigned long long dt) {
static procfile *ff = NULL;
static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
if(!path_to_get_hw_sector_size[0]) {
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/block/%s/queue/hw_sector_size");
- snprintf(path_to_get_hw_sector_size, FILENAME_MAX, "%s%s", global_host_prefix, config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", filename));
+ snprintf(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", filename));
}
ff = procfile_readall(ff);
// I/O completion time and the backlog that may be accumulating.
backlog_ms = strtoull(procfile_lineword(ff, l, 13), NULL, 10); // rq_ticks
-
int def_enabled = 0;
// remove slashes from disk names
char *s;
for(s = disk; *s ;s++) if(*s == '/') *s = '_';
+ struct disk *d = get_disk(major, minor);
+ if(d->partition_id == -1)
+ def_enabled = enable_new_disks;
+ else
+ def_enabled = 0;
+
+/*
switch(major) {
case 9: // MDs
case 43: // network block
case 199: // veritas
case 201: // veritas
case 251: // dm
+ case 253: // virtio
def_enabled = enable_new_disks;
break;
case 135: // scsi
case 153: // raid
case 202: // xen
- case 253: // virtio
+ case 254: // virtio3
case 256: // flash
case 257: // flash
case 259: // nvme0n1 issue #119
def_enabled = 0;
break;
}
+*/
int ddo_io = do_io, ddo_ops = do_ops, ddo_mops = do_mops, ddo_iotime = do_iotime, ddo_qops = do_qops, ddo_util = do_util, ddo_backlog = do_backlog;
#include "common.h"
#include "log.h"
#include "procfile.h"
+#include "../config.h"
#define PF_PREFIX "PROCFILE"
#define PF_CHAR_IS_SEPARATOR ' '
#define PF_CHAR_IS_NEWLINE 'N'
#define PF_CHAR_IS_WORD 'W'
+#define PF_CHAR_IS_QUOTE 'Q'
+#define PF_CHAR_IS_OPEN 'O'
+#define PF_CHAR_IS_CLOSE 'C'
void procfile_close(procfile *ff) {
debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", ff->filename);
procfile *procfile_parser(procfile *ff) {
debug(D_PROCFILE, PF_PREFIX ": Parsing file '%s'", ff->filename);
- char *s = ff->data, *e = ff->data, *t = ff->data;
+ char *s = ff->data, *e = &ff->data[ff->len], *t = ff->data, quote = 0;
uint32_t l = 0, w = 0;
- e += ff->len;
+ int opened = 0;
ff->lines = pflines_add(ff->lines, w);
if(unlikely(!ff->lines)) goto cleanup;
while(likely(s < e)) {
+ // we are not at the end
+
switch(ff->separators[(int)(*s)]) {
+ case PF_CHAR_IS_OPEN:
+ if(s == t) {
+ opened++;
+ t = ++s;
+ }
+ else if(opened) {
+ opened++;
+ s++;
+ }
+ else
+ s++;
+ continue;
+
+ case PF_CHAR_IS_CLOSE:
+ if(opened) {
+ opened--;
+
+ if(!opened) {
+ *s = '\0';
+ ff->words = pfwords_add(ff->words, t);
+ if(unlikely(!ff->words)) goto cleanup;
+
+ ff->lines->lines[l].words++;
+ w++;
+
+ t = ++s;
+ }
+ else
+ s++;
+ }
+ else
+ s++;
+ continue;
+
+ case PF_CHAR_IS_QUOTE:
+ if(unlikely(!quote && s == t)) {
+ // quote opened at the beginning
+ quote = *s;
+ t = ++s;
+ }
+ else if(unlikely(quote && quote == *s)) {
+ // quote closed
+ quote = 0;
+
+ *s = '\0';
+ ff->words = pfwords_add(ff->words, t);
+ if(unlikely(!ff->words)) goto cleanup;
+
+ ff->lines->lines[l].words++;
+ w++;
+
+ t = ++s;
+ }
+ else
+ s++;
+ continue;
+
case PF_CHAR_IS_SEPARATOR:
- if(likely(s == t)) {
+ if(unlikely(quote || opened)) {
+ // we are inside a quote
+ s++;
+ continue;
+ }
+
+ if(unlikely(s == t)) {
// skip all leading white spaces
t = ++s;
continue;
}
}
- if(likely(s != t)) {
+ if(likely(s > t && t < e)) {
// the last word
- if(likely(ff->len < ff->size)) *s = '\0';
+ if(likely(ff->len < ff->size))
+ *s = '\0';
else {
// we are going to loose the last byte
ff->data[ff->size - 1] = '\0';
while(likely(ffd != ffe)) *ffs++ = *ffd++;
// set the separators
- if(unlikely(!separators)) separators = " \t=|";
+ if(unlikely(!separators))
+ separators = " \t=|";
+
ffs = ff->separators;
const char *s = separators;
- while(likely(*s)) ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
+ while(likely(*s))
+ ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
+}
+
+void procfile_set_quotes(procfile *ff, const char *quotes) {
+ // remove all quotes
+ int i;
+ for(i = 0; i < 256 ; i++)
+ if(ff->separators[i] == PF_CHAR_IS_QUOTE)
+ ff->separators[i] = PF_CHAR_IS_WORD;
+
+ // if nothing given, return
+ if(unlikely(!quotes || !*quotes))
+ return;
+
+ // set the quotes
+ char *ffs = ff->separators;
+ const char *s = quotes;
+ while(likely(*s))
+ ffs[(int)*s++] = PF_CHAR_IS_QUOTE;
+}
+
+void procfile_set_open_close(procfile *ff, const char *open, const char *close) {
+ // remove all open/close
+ int i;
+ for(i = 0; i < 256 ; i++)
+ if(ff->separators[i] == PF_CHAR_IS_OPEN || ff->separators[i] == PF_CHAR_IS_CLOSE)
+ ff->separators[i] = PF_CHAR_IS_WORD;
+
+ // if nothing given, return
+ if(unlikely(!open || !*open || !close || !*close))
+ return;
+
+ // set the openings
+ char *ffs = ff->separators;
+ const char *s = open;
+ while(likely(*s))
+ ffs[(int)*s++] = PF_CHAR_IS_OPEN;
+
+ s = close;
+ while(likely(*s))
+ ffs[(int)*s++] = PF_CHAR_IS_CLOSE;
}
procfile *procfile_open(const char *filename, const char *separators, uint32_t flags) {
// example walk-through a procfile parsed file
extern void procfile_print(procfile *ff);
+extern void procfile_set_quotes(procfile *ff, const char *quotes);
+extern void procfile_set_open_close(procfile *ff, const char *open, const char *close);
+
// ----------------------------------------------------------------------------
// set this to 1, to have procfile adapt its initial buffer allocation to the max allocation used so far
{
debug(D_RRD_CALLS, "rrdset_save_all()");
+ // let it log a few error messages
+ error_log_limit_reset();
+
RRDSET *st;
RRDDIM *rd;
// generate the local date time
struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
if(!tm) { error("localtime() failed."); continue; }
- buffer_date(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+ buffer_date(wb, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
}
if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
#include "rrd2json.h"
#include "web_client.h"
+#include "../config.h"
#define INITIAL_WEB_DATA_LENGTH 16384
#define WEB_REQUEST_LENGTH 16384
static uid_t owner_uid = 0;
if(unlikely(!web_owner)) {
- web_owner = config_get("global", "web files owner", NETDATA_USER);
+ web_owner = config_get("global", "web files owner", config_get("global", "run as user", ""));
if(!web_owner || !*web_owner)
owner_uid = geteuid();
else {
+ // getpwnam() is not thread safe,
+ // but we have called this function once
+ // while single threaded
struct passwd *pw = getpwnam(web_owner);
if(!pw) {
error("User %s is not present. Ignoring option.", web_owner);
static gid_t owner_gid = 0;
if(unlikely(!web_group)) {
- web_group = config_get("global", "web files group", config_get("global", "web files owner", NETDATA_USER));
+ web_group = config_get("global", "web files group", config_get("global", "web files owner", ""));
if(!web_group || !*web_group)
owner_gid = getegid();
else {
+ // getgrnam() is not thread safe,
+ // but we have called this function once
+ // while single threaded
struct group *gr = getgrnam(web_group);
if(!gr) {
error("Group %s is not present. Ignoring option.", web_group);
extern struct web_client *web_clients;
extern uid_t web_files_uid(void);
+extern uid_t web_files_gid(void);
extern struct web_client *web_client_create(int listener);
extern struct web_client *web_client_free(struct web_client *w);
#include "global_statistics.h"
#include "rrd.h"
#include "rrd2json.h"
+#include "../config.h"
int listen_backlog = LISTEN_BACKLOG;
MAINTAINERCLEANFILES= $(srcdir)/Makefile.in
CLEANFILES = \
netdata-openrc \
+ netdata.logrotate \
netdata.service \
netdata-init-d \
$(NULL)
nodist_noinst_DATA = \
netdata-openrc \
+ netdata.logrotate \
netdata.service \
netdata-init-d \
$(NULL)
dist_noinst_DATA = \
netdata-openrc.in \
+ netdata.logrotate.in \
netdata.service.in \
netdata-init-d.in \
+ netdata.conf \
$(NULL)
service_start()
{
- printf "%-50s" "Starting $DAEMON..."
+ echo "Starting $DAEMON..."
daemon $DAEMON_PATH/$DAEMON $DAEMONOPTS
+ RETVAL=$?
echo
+ return $RETVAL
}
service_stop()
{
printf "%-50s" "Stopping $DAEMON..."
killproc -p ${PIDFILE} -d ${STOP_TIMEOUT} $DAEMON
- rm -f ${PIDFILE}
+ RETVAL=$?
+ if [ $RETVAL -eq 0 ]; then
+ rm -f ${PIDFILE}
+ fi
echo
+ return $RETVAL
}
service_status()
--- /dev/null
+# NetData Configuration
+#
+# To see defaults, grab one from your instance:
+# http://localhost:19999/netdata.conf
+
+# global netdata configuration
+
+[global]
+ run as user = netdata
+ web files owner = root
+ web files group = netdata
--- /dev/null
+@localstatedir_POST@/log/netdata/*.log {
+ daily
+ missingok
+ rotate 14
+ compress
+ delaycompress
+ notifempty
+ sharedscripts
+ postrotate
+ if service netdata status > /dev/null ; then \
+ service netdata restart > /dev/null; \
+ fi;
+ endscript
+}
+
[Unit]
-Description=netdata
+Description=Linux real time system monitoring, over the web
After=network.target httpd.service squid.service nfs-server.service mysqld.service named.service postfix.service
[Service]
MAINTAINERCLEANFILES= $(srcdir)/Makefile.in
dist_web_DATA = \
- robots.txt \
- index.html \
+ robots.txt \
+ index.html \
demo.html \
demo2.html \
tv.html \
- dashboard.html \
- dashboard.js \
- dashboard.css \
- dashboard.slate.css \
+ dashboard.html \
+ dashboard.js \
+ dashboard.css \
+ dashboard.slate.css \
favicon.ico \
netdata-swagger.yaml \
netdata-swagger.json \
- version.txt \
- $(NULL)
+ version.txt \
+ $(NULL)
webolddir=$(webdir)/old
dist_webold_DATA = \
- old/datasource.html \
- old/index.html \
- old/index.js \
- old/netdata.js \
- old/theme.css \
- $(NULL)
+ old/datasource.html \
+ old/index.html \
+ old/index.js \
+ old/netdata.js \
+ old/theme.css \
+ $(NULL)
weblibdir=$(webdir)/lib
dist_weblib_DATA = \
- lib/dygraph-combined.js \
- lib/dygraph-smooth-plotter.js \
- lib/jquery-1.12.0.min.js \
- lib/jquery.peity.min.js \
- lib/jquery.sparkline.min.js \
- lib/morris.min.js \
- lib/raphael-min.js \
+ lib/dygraph-combined.js \
+ lib/dygraph-smooth-plotter.js \
+ lib/jquery-1.12.0.min.js \
+ lib/jquery.peity.min.js \
+ lib/jquery.sparkline.min.js \
+ lib/morris.min.js \
+ lib/raphael-min.js \
lib/jquery.easypiechart.min.js \
lib/jquery.nanoscroller.min.js \
- lib/bootstrap.min.js \
+ lib/bootstrap.min.js \
lib/ElementQueries.js \
lib/ResizeSensor.js \
- lib/bootstrap-toggle.min.js \
- lib/c3.min.js \
- lib/d3.min.js \
- lib/gauge.min.js \
- $(NULL)
+ lib/bootstrap-toggle.min.js \
+ lib/c3.min.js \
+ lib/d3.min.js \
+ lib/gauge.min.js \
+ $(NULL)
webcssdir=$(webdir)/css
dist_webcss_DATA = \
- css/morris.css \
- css/bootstrap.min.css \
- css/bootstrap-theme.min.css \
- css/bootstrap.slate.min.css \
+ css/morris.css \
+ css/bootstrap.min.css \
+ css/bootstrap-theme.min.css \
+ css/bootstrap.slate.min.css \
css/font-awesome.min.css \
- css/bootstrap-toggle.min.css \
- css/c3.min.css \
- $(NULL)
+ css/bootstrap-toggle.min.css \
+ css/c3.min.css \
+ $(NULL)
webfontsdir=$(webdir)/fonts
dist_webfonts_DATA = \
- fonts/glyphicons-halflings-regular.eot \
- fonts/glyphicons-halflings-regular.svg \
- fonts/glyphicons-halflings-regular.ttf \
- fonts/glyphicons-halflings-regular.woff \
- fonts/glyphicons-halflings-regular.woff2 \
+ fonts/glyphicons-halflings-regular.eot \
+ fonts/glyphicons-halflings-regular.svg \
+ fonts/glyphicons-halflings-regular.ttf \
+ fonts/glyphicons-halflings-regular.woff \
+ fonts/glyphicons-halflings-regular.woff2 \
fonts/FontAwesome.otf \
fonts/fontawesome-webfont.eot \
fonts/fontawesome-webfont.svg \
fonts/fontawesome-webfont.ttf \
fonts/fontawesome-webfont.woff \
fonts/fontawesome-webfont.woff2 \
- $(NULL)
+ $(NULL)
webimagesdir=$(webdir)/images
dist_webimages_DATA = \
images/seo-performance-512.png \
images/seo-performance-multi-size.ico \
images/seo-performance-multi-size.icns \
- $(NULL)
+ $(NULL)
version.txt:
if test -d "$(top_srcdir)/.git"; then \
- if git --git-dir="$(top_srcdir)/.git" log -n 1 > v.tmp; then \
- grep ^commit\ v.tmp | cut -d" " -f2 > version.txt; \
- rm -f v.tmp; \
- else \
- rm -f v.tmp; \
- echo "0" > version.txt; \
- fi; \
- else \
- echo "0" > version.txt; \
- fi
+ git --git-dir="$(top_srcdir)/.git" log -n 1 --format=%H; \
+ fi > $@.tmp
+ test -s $@.tmp || echo 0 > $@.tmp
+ mv $@.tmp $@
.PHONY: version.txt
// var netdataNoC3 = true; // do not use C3
// var netdataNoBootstrap = true; // do not load bootstrap
// var netdataDontStart = true; // do not start the thread to process the charts
+// var netdataErrorCallback = null; // Callback function that will be invoked upon error
//
// You can also set the default netdata server, using the following.
// When this variable is not set, we assume the page is hosted on your
after: -600, // panning
pixels_per_point: 1, // the detail of the chart
fill_luminance: 0.8 // luminance of colors in solit areas
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
// global options
destroy_on_hide: false, // destroy charts when they are not visible
show_help: true, // when enabled the charts will show some help
+ show_help_delay_show_ms: 500,
+ show_help_delay_hide_ms: 0,
eliminate_zero_dimensions: true, // do not show dimensions with just zeros
color_fill_opacity_area: 0.2,
color_fill_opacity_stacked: 0.8,
- pan_and_zoom_step: 0.1, // the increment when panning and zooming with the toolbox
+ pan_and_zoom_factor: 0.25, // the increment when panning and zooming with the toolbox
+ pan_and_zoom_factor_multiplier_control: 2.0,
+ pan_and_zoom_factor_multiplier_shift: 3.0,
+ pan_and_zoom_factor_multiplier_alt: 4.0,
setOptionCallback: function() { ; }
},
libraries: false,
dygraph: false
}
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
NETDATA.localStorage.current[key.toString()] = ret;
return ret;
- }
+ };
NETDATA.localStorageSet = function(key, value, callback) {
if(typeof value === 'undefined' || value === 'undefined') {
NETDATA.localStorage.current[key.toString()] = value;
return value;
- }
+ };
NETDATA.localStorageGetRecursive = function(obj, prefix, callback) {
for(var i in obj) {
obj[i] = NETDATA.localStorageGet(prefix + '.' + i.toString(), obj[i], callback);
}
- }
+ };
NETDATA.setOption = function(key, value) {
if(key.toString() === 'setOptionCallback') {
}
return true;
- }
+ };
NETDATA.getOption = function(key) {
return NETDATA.options.current[key.toString()];
- }
+ };
// read settings from local storage
NETDATA.localStorageGetRecursive(NETDATA.options.current, 'options', null);
101: { message: "Cannot load jQuery", alert: true },
402: { message: "Chart library not found", alert: false },
403: { message: "Chart library not enabled/is failed", alert: false },
- 404: { message: "Chart not found", alert: false }
+ 404: { message: "Chart not found", alert: false },
+ 405: { message: "Cannot download charts index from server", alert: true },
+ 406: { message: "Invalid charts index downloaded from server", alert: true }
};
NETDATA.errorLast = {
code: 0,
console.log("ERROR " + code + ": " + NETDATA.errorCodes[code].message + ": " + msg);
- if(NETDATA.errorCodes[code].alert)
+ var ret = true;
+ if(typeof netdataErrorCallback === 'function') {
+ ret = netdataErrorCallback('system', code, msg);
+ }
+
+ if(ret && NETDATA.errorCodes[code].alert)
alert("ERROR " + code + ": " + NETDATA.errorCodes[code].message + ": " + msg);
- }
+ };
NETDATA.errorReset = function() {
NETDATA.errorLast.code = 0;
cache: false
})
.done(function(data) {
- var h = NETDATA.chartRegistry.fixid(host);
- //console.log('downloaded all charts from ' + host + ' (' + h + ')');
- self.charts[h] = data.charts;
+ if(data !== null) {
+ var h = NETDATA.chartRegistry.fixid(host);
+ self.charts[h] = data.charts;
+ }
+ else NETDATA.error(406, host + '/api/v1/charts');
+
if(typeof callback === 'function')
callback(data);
})
.fail(function() {
+ NETDATA.error(405, host + '/api/v1/charts');
+
if(typeof callback === 'function')
callback(null);
});
return true;
}
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
// dimensions selection
this.value_div = null;
this.color = NETDATA.themes.current.foreground;
- if(parent.selected === parent.unselected)
+ if(parent.selected_count > parent.unselected_count)
this.selected = true;
else
this.selected = false;
this.setOptions(name_div, value_div, color);
- }
+ };
dimensionStatus.prototype.invalidate = function() {
this.name_div = null;
this.value_div = null;
this.enabled = false;
- }
+ };
dimensionStatus.prototype.setOptions = function(name_div, value_div, color) {
this.color = color;
this.enabled = true;
this.setHandler();
- }
+ };
dimensionStatus.prototype.setHandler = function() {
if(this.enabled === false) return;
ds.parent.state.redrawChart();
}
- }
+ };
dimensionStatus.prototype.select = function() {
if(this.enabled === false) return;
this.name_div.className = 'netdata-legend-name selected';
this.value_div.className = 'netdata-legend-value selected';
this.selected = true;
- }
+ };
dimensionStatus.prototype.unselect = function() {
if(this.enabled === false) return;
this.name_div.className = 'netdata-legend-name not-selected';
this.value_div.className = 'netdata-legend-value hidden';
this.selected = false;
- }
+ };
dimensionStatus.prototype.isSelected = function() {
return(this.enabled === true && this.selected === true);
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
this.dimensions = {};
this.selected_count = 0;
this.unselected_count = 0;
- }
+ };
dimensionsVisibility.prototype.dimensionAdd = function(label, name_div, value_div, color) {
if(typeof this.dimensions[label] === 'undefined') {
this.dimensions[label].setOptions(name_div, value_div, color);
return this.dimensions[label];
- }
+ };
dimensionsVisibility.prototype.dimensionGet = function(label) {
return this.dimensions[label];
- }
+ };
dimensionsVisibility.prototype.invalidateAll = function() {
for(var d in this.dimensions)
this.dimensions[d].invalidate();
- }
+ };
dimensionsVisibility.prototype.selectAll = function() {
for(var d in this.dimensions)
this.dimensions[d].select();
- }
+ };
dimensionsVisibility.prototype.countSelected = function() {
var i = 0;
if(this.dimensions[d].isSelected()) i++;
return i;
- }
+ };
dimensionsVisibility.prototype.selectNone = function() {
for(var d in this.dimensions)
this.dimensions[d].unselect();
- }
+ };
dimensionsVisibility.prototype.selected2BooleanArray = function(array) {
var ret = new Array();
}
return ret;
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
* show an error instead of the chart
*/
var error = function(msg) {
- that.element.innerHTML = that.id + ': ' + msg;
- that.enabled = false;
- that.current = that.pan;
- }
+ var ret = true;
+
+ if(typeof netdataErrorCallback === 'function') {
+ ret = netdataErrorCallback('chart', that.id, msg);
+ }
+
+ if(ret) {
+ that.element.innerHTML = that.id + ': ' + msg;
+ that.enabled = false;
+ that.current = that.pan;
+ }
+ };
// GUID - a unique identifier for the chart
this.uuid = NETDATA.guid();
that.tm.last_dom_created = new Date().getTime();
showLoading();
- }
+ };
/* init() private
- * initialize state viariables
+ * initialize state variables
* destroy all (possibly) created state elements
* create the basic DOM for a chart
*/
last_hidden: 0, // the time the chart was hidden
last_unhidden: 0, // the time the chart was unhidden
last_autorefreshed: 0 // the time the chart was last refreshed
- },
+ };
that.data = null; // the last data as downloaded from the netdata server
that.data_url = 'invalid://'; // string - the last url used to update the chart
createDOM();
that.setMode('auto');
- }
+ };
var maxMessageFontSize = function() {
// normally we want a font size, as tall as the element
// set it
that.element_message.style.fontSize = h.toString() + 'px';
that.element_message.style.paddingTop = paddingTop.toString() + 'px';
- }
+ };
var showMessage = function(msg) {
that.element_message.className = 'netdata-message';
that.element_message.innerHTML = msg;
- this.element_message.style.fontSize = 'x-small';
+ that.element_message.style.fontSize = 'x-small';
that.element_message.style.paddingTop = '0px';
that.___messageHidden___ = undefined;
- }
+ };
var showMessageIcon = function(icon) {
that.element_message.innerHTML = icon;
that.element_message.className = 'netdata-message icon';
maxMessageFontSize();
that.___messageHidden___ = undefined;
- }
+ };
var hideMessage = function() {
if(typeof that.___messageHidden___ === 'undefined') {
that.___messageHidden___ = true;
that.element_message.className = 'netdata-message hidden';
}
- }
+ };
var showRendering = function() {
var icon;
icon = '<i class="fa fa-area-chart"></i>';
showMessageIcon(icon + ' netdata');
- }
+ };
var showLoading = function() {
if(that.chart_created === false) {
return true;
}
return false;
- }
+ };
var isHidden = function() {
if(typeof that.___chartIsHidden___ !== 'undefined')
return true;
return false;
- }
+ };
// hide the chart, when it is not visible - called from isVisible()
var hideChart = function() {
}
that.___chartIsHidden___ = true;
- }
+ };
// unhide the chart, when it is visible - called from isVisible()
var unhideChart = function() {
resizeChart();
hideMessage();
}
- }
+ };
var canBeRendered = function() {
if(isHidden() === true || that.isVisible(true) === false)
return false;
return true;
- }
+ };
// https://github.com/petkaantonov/bluebird/wiki/Optimization-killers
var callChartLibraryUpdateSafely = function(data) {
}
return true;
- }
+ };
// https://github.com/petkaantonov/bluebird/wiki/Optimization-killers
var callChartLibraryCreateSafely = function(data) {
that.chart_created = true;
that.updates_since_last_creation = 0;
return true;
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
// Chart Resize
that.tm.last_resized = new Date().getTime();
}
- }
+ };
// this is the actual chart resize algorithm
// it will:
NETDATA.options.auto_refresher_stop_until = 0;
};
}
- }
+ };
var noDataToShow = function() {
//that.element_chart.style.display = 'none';
//if(that.element_legend !== null) that.element_legend.style.display = 'none';
//that.___chartIsHidden___ = true;
- }
+ };
// ============================================================================================================
// PUBLIC FUNCTIONS
this.error = function(msg) {
error(msg);
- }
+ };
this.setMode = function(m) {
if(this.current !== null && this.current.name === m) return;
this.current.force_after_ms = null;
this.tm.last_mode_switch = new Date().getTime();
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
// global selection sync
NETDATA.globalSelectionSync.dont_sync_before = new Date().getTime() + ms;
else
NETDATA.globalSelectionSync.dont_sync_before = new Date().getTime() + NETDATA.options.current.sync_selection_delay;
- }
+ };
// can we globally apply selection sync?
this.globalSelectionSyncAbility = function() {
return false;
return true;
- }
+ };
this.globalSelectionSyncIsMaster = function() {
if(NETDATA.globalSelectionSync.state === this)
return true;
else
return false;
- }
+ };
// this chart is the master of the global selection sync
this.globalSelectionSyncBeMaster = function() {
}
// this.globalSelectionSyncDelay(100);
- }
+ };
// can the chart participate to the global selection sync as a slave?
this.globalSelectionSyncIsEligible = function() {
return true;
return false;
- }
+ };
// this chart becomes a slave of the global selection sync
this.globalSelectionSyncBeSlave = function() {
if(NETDATA.globalSelectionSync.state !== this)
NETDATA.globalSelectionSync.slaves.push(this);
- }
+ };
// sync all the visible charts to the given time
// this is to be called from the chart libraries
$.each(NETDATA.globalSelectionSync.slaves, function(i, st) {
st.setSelection(t);
});
- }
+ };
// stop syncing all charts to the given time
this.globalSelectionSyncStop = function() {
}
this.clearSelection();
- }
+ };
this.setSelection = function(t) {
if(typeof this.library.setSelection === 'function') {
this.log('selection set to ' + t.toString());
return this.selected;
- }
+ };
this.clearSelection = function() {
if(this.selected === true) {
}
return this.selected;
- }
+ };
// find if a timestamp (ms) is shown in the current chart
this.timeIsVisible = function(t) {
if(t >= this.data_after && t <= this.data_before)
return true;
return false;
- },
+ };
this.calculateRowForTime = function(t) {
if(this.timeIsVisible(t) === false) return -1;
return Math.floor((t - this.data_after) / this.data_update_every);
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
// console logging
this.log = function(msg) {
console.log(this.id + ' (' + this.library_name + ' ' + this.uuid + '): ' + msg);
- }
+ };
this.pauseChart = function() {
if(this.paused === false) {
this.paused = true;
}
- }
+ };
this.unpauseChart = function() {
if(this.paused === true) {
this.paused = false;
}
- }
+ };
this.resetChart = function(dont_clear_master, dont_update) {
if(this.debug === true)
if(dont_update !== true && this.isVisible() === true) {
this.updateChart();
}
- }
+ };
this.updateChartPanOrZoom = function(after, before) {
var logme = 'updateChartPanOrZoom(' + after + ', ' + before + '): ';
this.log(logme);
if(before < after) {
- this.log(logme + 'flipped parameters, rejecting it.');
+ if(this.debug === true)
+ this.log(logme + 'flipped parameters, rejecting it.');
+
return false;
}
this.current.force_before_ms = before;
NETDATA.globalPanAndZoom.setMaster(this, after, before);
return ret;
- }
+ };
this.legendFormatValue = function(value) {
if(value === null || value === 'undefined') return '-';
if(abs >= 1 ) return (Math.round(value * 100) / 100).toLocaleString();
if(abs >= 0.1 ) return (Math.round(value * 1000) / 1000).toLocaleString();
return (Math.round(value * 10000) / 10000).toLocaleString();
- }
+ };
this.legendSetLabelValue = function(label, value) {
var series = this.element_legend_childs.series[label];
if(series.value !== null) series.value.innerHTML = s;
if(series.user !== null) series.user.innerHTML = r;
- }
+ };
this.legendSetDate = function(ms) {
if(typeof ms !== 'number') {
if(this.element_legend_childs.title_units)
this.element_legend_childs.title_units.innerHTML = this.units;
- }
+ };
this.legendShowUndefined = function() {
if(this.element_legend_childs.title_date)
this.legendSetLabelValue(label, null);
}
}
- }
+ };
this.legendShowLatestValues = function() {
if(this.chart === null) return;
else
this.legendSetLabelValue(label, this.data.view_latest_values[i]);
}
- }
+ };
this.legendReset = function() {
this.legendShowLatestValues();
- }
+ };
// this should be called just ONCE per dimension per chart
this._chartDimensionColor = function(label) {
this.colors.push(this.colors_assigned[label]);
return this.colors_assigned[label];
- }
+ };
this.chartColors = function() {
if(this.colors !== null) return this.colors;
this.colors = new Array();
this.colors_available = new Array();
+ var i, len;
var c = $(this.element).data('colors');
// this.log('read colors: ' + c);
var added = 0;
while(added < 20) {
- for(var i = 0, len = c.length; i < len ; i++) {
+ for(i = 0, len = c.length; i < len ; i++) {
added++;
this.colors_available.push(c[i]);
// this.log('adding color: ' + c[i]);
}
// push all the standard colors too
- for(var i = 0, len = NETDATA.themes.current.colors.length; i < len ; i++)
+ for(i = 0, len = NETDATA.themes.current.colors.length; i < len ; i++)
this.colors_available.push(NETDATA.themes.current.colors[i]);
return this.colors;
- }
+ };
this.legendUpdateDOM = function() {
var needed = false;
if(user_id !== null) {
user_element = document.getElementById(user_id) || null;
if(user_element === null)
- me.log('Cannot find element with id: ' + user_id);
+ state.log('Cannot find element with id: ' + user_id);
}
state.element_legend_childs.series[name] = {
this.element_legend.innerHTML = '';
if(this.library.toolboxPanAndZoom !== null) {
+
+ function get_pan_and_zoom_step(event) {
+ if (event.ctrlKey)
+ return NETDATA.options.current.pan_and_zoom_factor * NETDATA.options.current.pan_and_zoom_factor_multiplier_control;
+
+ else if (event.shiftKey)
+ return NETDATA.options.current.pan_and_zoom_factor * NETDATA.options.current.pan_and_zoom_factor_multiplier_shift;
+
+ else if (event.altKey)
+ return NETDATA.options.current.pan_and_zoom_factor * NETDATA.options.current.pan_and_zoom_factor_multiplier_alt;
+
+ else
+ return NETDATA.options.current.pan_and_zoom_factor;
+ }
+
this.element_legend_childs.toolbox.className += ' netdata-legend-toolbox';
this.element.appendChild(this.element_legend_childs.toolbox);
this.element_legend_childs.toolbox.appendChild(this.element_legend_childs.toolbox_left);
this.element_legend_childs.toolbox_left.onclick = function(e) {
e.preventDefault();
- var dt = (that.view_before - that.view_after) * NETDATA.options.current.pan_and_zoom_step;
- var before = that.view_before - dt;
- var after = that.view_after - dt;
+
+ var step = (that.view_before - that.view_after) * get_pan_and_zoom_step(e);
+ var before = that.view_before - step;
+ var after = that.view_after - step;
if(after >= that.netdata_first)
that.library.toolboxPanAndZoom(that, after, before);
- }
+ };
if(NETDATA.options.current.show_help === true)
$(this.element_legend_childs.toolbox_left).popover({
container: "body",
html: true,
trigger: 'hover',
placement: 'bottom',
- delay: 100,
+ delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms },
title: 'Pan Left',
content: 'Pan the chart to the left. You can also <b>drag it</b> with your mouse or your finger (on touch devices).<br/><small>Help, can be disabled from the settings.</small>'
});
this.element_legend_childs.toolbox_reset.onclick = function(e) {
e.preventDefault();
NETDATA.resetAllCharts(that);
- }
+ };
if(NETDATA.options.current.show_help === true)
$(this.element_legend_childs.toolbox_reset).popover({
container: "body",
html: true,
trigger: 'hover',
placement: 'bottom',
- delay: 100,
+ delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms },
title: 'Chart Reset',
content: 'Reset all the charts to their default auto-refreshing state. You can also <b>double click</b> the chart contents with your mouse or your finger (on touch devices).<br/><small>Help, can be disabled from the settings.</small>'
});
this.element_legend_childs.toolbox.appendChild(this.element_legend_childs.toolbox_right);
this.element_legend_childs.toolbox_right.onclick = function(e) {
e.preventDefault();
- var dt = (that.view_before - that.view_after) * NETDATA.options.current.pan_and_zoom_step;
- var before = that.view_before + dt;
- var after = that.view_after + dt;
+ var step = (that.view_before - that.view_after) * get_pan_and_zoom_step(e);
+ var before = that.view_before + step;
+ var after = that.view_after + step;
if(before <= that.netdata_last)
that.library.toolboxPanAndZoom(that, after, before);
- }
+ };
if(NETDATA.options.current.show_help === true)
$(this.element_legend_childs.toolbox_right).popover({
container: "body",
html: true,
trigger: 'hover',
placement: 'bottom',
- delay: 100,
+ delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms },
title: 'Pan Right',
content: 'Pan the chart to the right. You can also <b>drag it</b> with your mouse or your finger (on touch devices).<br/><small>Help, can be disabled from the settings.</small>'
});
this.element_legend_childs.toolbox.appendChild(this.element_legend_childs.toolbox_zoomin);
this.element_legend_childs.toolbox_zoomin.onclick = function(e) {
e.preventDefault();
- var dt = (that.view_before - that.view_after) * NETDATA.options.current.pan_and_zoom_step;
+ var dt = ((that.view_before - that.view_after) * (get_pan_and_zoom_step(e) * 0.8) / 2);
var before = that.view_before - dt;
var after = that.view_after + dt;
that.library.toolboxPanAndZoom(that, after, before);
- }
+ };
if(NETDATA.options.current.show_help === true)
$(this.element_legend_childs.toolbox_zoomin).popover({
container: "body",
html: true,
trigger: 'hover',
placement: 'bottom',
- delay: 100,
+ delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms },
title: 'Chart Zoom In',
content: 'Zoom in the chart. You can also press SHIFT and select an area of the chart to zoom in. On Chrome and Opera, you can press the SHIFT or the ALT keys and then use the mouse wheel to zoom in or out.<br/><small>Help, can be disabled from the settings.</small>'
});
this.element_legend_childs.toolbox.appendChild(this.element_legend_childs.toolbox_zoomout);
this.element_legend_childs.toolbox_zoomout.onclick = function(e) {
e.preventDefault();
- var dt = (that.view_before - that.view_after) * NETDATA.options.current.pan_and_zoom_step;
+ var dt = (((that.view_before - that.view_after) / (1.0 - (get_pan_and_zoom_step(e) * 0.8)) - (that.view_before - that.view_after)) / 2);
var before = that.view_before + dt;
var after = that.view_after - dt;
that.library.toolboxPanAndZoom(that, after, before);
- }
+ };
if(NETDATA.options.current.show_help === true)
$(this.element_legend_childs.toolbox_zoomout).popover({
container: "body",
html: true,
trigger: 'hover',
placement: 'bottom',
- delay: 100,
+ delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms },
title: 'Chart Zoom Out',
content: 'Zoom out the chart. On Chrome and Opera, you can also press the SHIFT or the ALT keys and then use the mouse wheel to zoom in or out.<br/><small>Help, can be disabled from the settings.</small>'
});
html: true,
trigger: 'hover',
placement: 'bottom',
- delay: 100,
+ delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms },
title: 'Chart Resize',
content: 'Drag this point with your mouse or your finger (on touch devices), to resize the chart vertically. You can also <b>double click it</b> or <b>double tap it</b> to reset between 2 states: the default and the one that fits all the values.<br/><small>Help, can be disabled from the settings.</small>'
});
trigger: 'hover',
placement: 'bottom',
title: 'Chart Legend',
- delay: 100,
+ delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms },
content: 'You can click or tap on the values or the labels to select dimentions. By pressing SHIFT or CONTROL, you can enable or disable multiple dimensions.<br/><small>Help, can be disabled from the settings.</small>'
});
}
$(this.element_legend_childs.nano).nanoScroller(this.element_legend_childs.nano_options);
this.legendShowLatestValues();
- }
+ };
this.hasLegend = function() {
if(typeof this.___hasLegendCache___ !== 'undefined')
this.___hasLegendCache___ = leg;
return leg;
- }
+ };
this.legendWidth = function() {
return (this.hasLegend())?140:0;
- }
+ };
this.legendHeight = function() {
return $(this.element).height();
- }
+ };
this.chartWidth = function() {
return $(this.element).width() - this.legendWidth();
- }
+ };
this.chartHeight = function() {
return $(this.element).height();
- }
+ };
this.chartPixelsPerPoint = function() {
// force an options provided detail
px = NETDATA.options.current.pixels_per_point;
return px;
- }
+ };
this.needsRecreation = function() {
return (
&& this.library.autoresize() === false
&& this.tm.last_resized < NETDATA.options.last_resized
);
- }
+ };
this.chartURL = function() {
var after, before, points_multiplier = 1;
if(NETDATA.options.debug.chart_data_url === true || this.debug === true)
this.log('chartURL(): ' + this.data_url + ' WxH:' + this.chartWidth() + 'x' + this.chartHeight() + ' points: ' + this.data_points + ' library: ' + this.library_name);
- }
+ };
this.redrawChart = function() {
if(this.data !== null)
this.updateChartWithData(this.data);
- }
+ };
this.updateChartWithData = function(data) {
if(this.debug === true)
if(this.refresh_dt_element !== null)
this.refresh_dt_element.innerHTML = this.refresh_dt_ms.toString();
- }
+ };
this.updateChart = function(callback) {
if(this.debug === true)
error('data download failed for url: ' + that.data_url);
})
.always(function() {
- this._updating = false;
+ that._updating = false;
if(typeof callback === 'function') callback();
});
return true;
- }
+ };
this.isVisible = function(nocache) {
if(typeof nocache === 'undefined')
this.___isVisible___ = true;
return this.___isVisible___;
}
- }
+ };
this.isAutoRefreshed = function() {
return (this.current.autorefresh);
- }
+ };
this.canBeAutoRefreshed = function() {
- now = new Date().getTime();
+ var now = new Date().getTime();
if(this.enabled === false) {
if(this.debug === true)
}
return false;
- }
+ };
this.autoRefresh = function(callback) {
if(this.canBeAutoRefreshed() === true) {
if(typeof callback !== 'undefined')
callback();
}
- }
+ };
this._defaultsFromDownloadedChart = function(chart) {
this.chart = chart;
if(this.units === null)
this.units = chart.units;
- }
+ };
// fetch the chart description from the netdata server
this.getChart = function(callback) {
if(typeof callback === 'function') callback();
});
}
- }
+ };
// ============================================================================================================
// INITIALIZATION
init();
- }
+ };
NETDATA.resetAllCharts = function(state) {
// first clear the global selection sync
// if we were not the master, reset our status too
// this is required because most probably the mouse
- // is over this chart, blocking it from autorefreshing
+ // is over this chart, blocking it from auto-refreshing
if(master === false && (state.paused === true || state.selected === true))
state.resetChart();
- }
+ };
// get or create a chart state, given a DOM element
NETDATA.chartState = function(element) {
$(element).data('netdata-state-object', state);
}
return state;
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
// Library functions
}
else if(typeof callback === "function")
callback();
- }
+ };
NETDATA._loadCSS = function(filename) {
// don't use jQuery here
if (typeof fileref !== 'undefined')
document.getElementsByTagName("head")[0].appendChild(fileref);
- }
+ };
NETDATA.colorHex2Rgb = function(hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
- }
+ };
NETDATA.colorLuminance = function(hex, lum) {
// validate hex string
}
return rgb;
- }
+ };
NETDATA.guid = function() {
function s4() {
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
- }
+ };
NETDATA.zeropad = function(x) {
if(x > -10 && x < 10) return '0' + x.toString();
else return x.toString();
- }
+ };
// user function to signal us the DOM has been
// updated.
NETDATA.updatedDom = function() {
NETDATA.options.updated_dom = true;
- }
+ };
NETDATA.ready = function(callback) {
NETDATA.options.pauseCallback = callback;
- }
+ };
NETDATA.pause = function(callback) {
if(NETDATA.options.pause === true)
callback();
else
NETDATA.options.pauseCallback = callback;
- }
+ };
NETDATA.unpause = function() {
NETDATA.options.pauseCallback = null;
NETDATA.options.updated_dom = true;
NETDATA.options.pause = false;
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
}, NETDATA.options.current.idle_between_charts);
}
}
- }
+ };
// this is part of the parallel refresher
// its cause is to refresh sequencially all the charts
// it will call the parallel refresher back
// as soon as it sees a chart that its chart library
// is initialized
- NETDATA.chartRefresher_unitialized = function() {
+ NETDATA.chartRefresher_uninitialized = function() {
if(NETDATA.options.updated_dom === true) {
// the dom has been updated
// get the dom parts again
if(state.library.initialized === true)
NETDATA.chartRefresher();
else
- state.autoRefresh(NETDATA.chartRefresher_unitialized);
+ state.autoRefresh(NETDATA.chartRefresher_uninitialized);
}
- }
+ };
NETDATA.chartRefresherWaitTime = function() {
return NETDATA.options.current.idle_parallel_loops;
- }
+ };
// the default refresher
// it will create 2 sets of charts:
// - the ones that can be refreshed in parallel
// - the ones that depend on something else
// the first set will be executed in parallel
- // the second will be given to NETDATA.chartRefresher_unitialized()
+ // the second will be given to NETDATA.chartRefresher_uninitialized()
NETDATA.chartRefresher = function() {
if(NETDATA.options.pause === true) {
// console.log('auto-refresher is paused');
setTimeout(NETDATA.chartRefresher,
NETDATA.chartRefresherWaitTime());
}
- }
+ };
NETDATA.parseDom = function(callback) {
NETDATA.options.last_page_scroll = new Date().getTime();
}
if(typeof callback === 'function') callback();
- }
+ };
// this is the main function - where everything starts
NETDATA.start = function() {
$('.modal').on('shown.bs.modal', NETDATA.onscroll);
NETDATA.parseDom(NETDATA.chartRefresher);
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
// peity
$(state.peity_instance).peity('line', state.peity_options);
return true;
- }
+ };
NETDATA.peityChartCreate = function(state, data) {
state.peity_instance = document.createElement('div');
NETDATA.peityChartUpdate(state, data);
return true;
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
// sparkline
$(state.element_chart).sparkline(data.result, state.sparkline_options);
return true;
- }
+ };
NETDATA.sparklineChartCreate = function(state, data) {
var self = $(state.element);
var drawNormalOnTop = self.data('sparkline-drawnormalontop') || undefined;
var xvalues = self.data('sparkline-xvalues') || undefined;
var chartRangeClip = self.data('sparkline-chartrangeclip') || undefined;
- var xvalues = self.data('sparkline-xvalues') || undefined;
var chartRangeMinX = self.data('sparkline-chartrangeminx') || undefined;
var chartRangeMaxX = self.data('sparkline-chartrangemaxx') || undefined;
var disableInteraction = self.data('sparkline-disableinteraction') || false;
if(typeof callback === "function")
callback();
});
- }
+ };
NETDATA.dygraphInitialize = function(callback) {
if(typeof netdataNoDygraphs === 'undefined' || !netdataNoDygraphs) {
}
return pcent;
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
// easy-pie-chart
state.easyPieChartEvent = {
timer: null,
value: 0,
- pcent: 0,
+ pcent: 0
};
}
state.gauge_instance.animationSpeed = speed;
state.___gaugeOld__.speed = speed;
- }
+ };
NETDATA.gaugeSet = function(state, value, min, max) {
if(typeof value !== 'number') value = 0;
NETDATA.gaugeChartCreate = function(state, data) {
var self = $(state.element);
- var chart = $(state.element_chart);
+ // var chart = $(state.element_chart);
var value = data.result[0];
var max = self.data('gauge-max-value') || null;
NETDATA.chartLibraries[library].url = url;
NETDATA.chartLibraries[library].initialized = true;
NETDATA.chartLibraries[library].enabled = true;
- }
+ };
// ----------------------------------------------------------------------------------------------------------------
// Start up
{
url: NETDATA.serverDefault + 'lib/bootstrap.min.js',
isAlreadyLoaded: function() {
+ // check if bootstrap is loaded
if(typeof $().emulateTransitionEnd == 'function')
return true;
else {
.fail(function() {
alert('Cannot load required JS library: ' + NETDATA.requiredJs[index].url);
})
- }
+ };
NETDATA.loadRequiredCSS = function(index) {
if(index >= NETDATA.requiredCSS.length)
NETDATA._loadCSS(NETDATA.requiredCSS[index].url);
NETDATA.loadRequiredCSS(++index);
- }
+ };
NETDATA.errorReset();
NETDATA.loadRequiredCSS(0);
NETDATA._loadjQuery(function() {
NETDATA.loadRequiredJs(0, function() {
+ if(typeof $().emulateTransitionEnd == 'function') {
+ // bootstrap is not available
+ NETDATA.options.current.show_help = false;
+ }
+
if(typeof netdataDontStart === 'undefined' || !netdataDontStart) {
if(NETDATA.options.debug.main_loop === true)
console.log('starting chart refresh thread');
<style>
- /* prevent body from hidding under the navbar */
+ /* prevent body from hiding under the navbar */
body {
padding-top: 50px;
}
</script>
<!-- load the dashboard manager - it will do the rest -->
- <script type="text/javascript" src="dashboard.js?v27"></script>
+ <script type="text/javascript" src="dashboard.js?v32"></script>
</head>
<body data-spy="scroll" data-target="#sidebar">
</div>
<div class="modal-body">
<div class="p">
- <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> is the fastest way to visualize metrics. It is a resource efficient, highly optimized system for collecting and visualizing any type of realtime timeseries data, from CPU usage, disk activity, SQL queries, API calls, web site visitors, etc.
+ <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> is the fastest way to visualize metrics. It is a resource efficient, highly optimized system for collecting and visualizing any type of real-time time series data, from CPU usage, disk activity, SQL queries, API calls, web site visitors, etc.
</div>
<div class="p">
<b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> tries to visualize the truth of <b>now</b>, in its <b>greatest detail</b>, so that you can get insights of what is happening now and what just happened, on your systems and applications.
While pressing the shift key, click on the contents of a chart and move the mouse to select an area, to zoom in. The other charts will follow too. Zooming is performed in two phases:
<ul>
<li>The already loaded chart contents are zoomed (low resolution)</li>
- <li>New data are transfered from the netdata server, to refresh the chart with possibly more detail.</li>
+ <li>New data are transferred from the netdata server, to refresh the chart with possibly more detail.</li>
</ul>
Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
</div>
<hr/>
<div class="p">
<h4>Legend Operations</h4>
- Click on the label or value of a dimension, will select / unselect this dimension.
+ Click on the label or value of a dimension, will select / un-select this dimension.
<br/>
- You can press any of the SHIFT or CONTROL keys and then click on legend labels or values, to select / unselect multiple dimensions.
+ You can press any of the SHIFT or CONTROL keys and then click on legend labels or values, to select / un-select multiple dimensions.
</div>
</div>
<div role="tabpanel" class="tab-pane" id="help_touch">
<hr/>
<div class="p">
<h4>Legend Operations</h4>
- Tap on the label or value of a dimension, will select / unselect this dimension.
+ Tap on the label or value of a dimension, will select / un-select this dimension.
</div>
</div>
</div>
<input id="eliminate_zero_dimensions" type="checkbox" checked data-toggle="toggle" data-on="Non Zero" data-off="All" data-width="110px">
</td>
<td class="option-info"><strong>Which dimensions to show?</strong><br/>
- <small>When set to <b>Non Zero</b>, dimensions that have all their values (within the current view) set to zero will not be transfered from the netdata server (except if all dimensions of the chart are zero, in which case this setting does nothing - all dimensions are transfered and shown). When set to <b>All</b>, all dimensions will always be shown. Set it to <b>Non Zero</b> to lower the data transfered between netdata and your browser, lower the CPU requirements of your browser (fewer lines to draw) and increase the focus on the legends (fewer entries at the legends).</small>
+ <small>When set to <b>Non Zero</b>, dimensions that have all their values (within the current view) set to zero will not be transferred from the netdata server (except if all dimensions of the chart are zero, in which case this setting does nothing - all dimensions are transferred and shown). When set to <b>All</b>, all dimensions will always be shown. Set it to <b>Non Zero</b> to lower the data transferred between netdata and your browser, lower the CPU requirements of your browser (fewer lines to draw) and increase the focus on the legends (fewer entries at the legends).</small>
</td>
</tr>
<tr class="option-row">
<div class="form-group">
<table>
<tr class="option-row">
- <td class="option-control"><input id="parallel_refresher" type="checkbox" checked data-toggle="toggle" data-on="Parallel" data-off="Sequencial" data-width="110px"></td>
+ <td class="option-control"><input id="parallel_refresher" type="checkbox" checked data-toggle="toggle" data-on="Parallel" data-off="Sequential" data-width="110px"></td>
<td class="option-info"><strong>Which chart refresh policy to use?</strong><br/>
- <small>When set to <b>parallel</b>, visible charts are refreshed in parallel (all queries are sent to netdata server in parallel) and are rendered asynchronously. When set to <b>sequencial</b> charts are refreshed one after another. Set it to parallel if your browser can cope with it (most modern browsers do), set it to sequencial if you work on an older/slower computer.</small>
+ <small>When set to <b>parallel</b>, visible charts are refreshed in parallel (all queries are sent to netdata server in parallel) and are rendered asynchronously. When set to <b>sequential</b> charts are refreshed one after another. Set it to parallel if your browser can cope with it (most modern browsers do), set it to sequential if you work on an older/slower computer.</small>
</td>
</tr>
<tr class="option-row" id="concurrent_refreshes_row">
<script>
-var demo_hostname = 'netdata.firehol.org';
-// var demo_hostname = 'box';
+var this_is_demo = null;
+function isdemo() {
+ if(this_is_demo !== null) return this_is_demo;
+ this_is_demo = false;
-if(document.location.hostname === demo_hostname) {
+ try {
+ if(typeof document.location.hostname === 'string')
+ this_is_demo = document.location.hostname.endsWith('.firehol.org');
+ }
+ catch(error) {
+ ;
+ }
+
+ return this_is_demo;
+}
+
+if(isdemo()) {
document.getElementById('masthead').style.display = 'block';
}
'apps': {
title: 'Applications',
- info: 'Per application statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics for applications of interest, defined in <code>/etc/netdata/apps_groups.conf</code> (the default is <a href="https://github.com/firehol/netdata/blob/master/conf.d/apps_groups.conf" target="_blank">here</a>). The plugin internaly builds a process tree (much like <code>ps fax</code> does), and groups processes together (evaluating both child and parent processes) so that the result is always a chart with a predefined set of dimensions (of course, only application groups found running are reported).<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning childs continiously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited childs of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealisting utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
+ info: 'Per application statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics for applications of interest, defined in <code>/etc/netdata/apps_groups.conf</code> (the default is <a href="https://github.com/firehol/netdata/blob/master/conf.d/apps_groups.conf" target="_blank">here</a>). The plugin internally builds a process tree (much like <code>ps fax</code> does), and groups processes together (evaluating both child and parent processes) so that the result is always a chart with a predefined set of dimensions (of course, only application groups found running are reported).<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning children continuously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited children of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealistic utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
height: 1.5
},
'users': {
title: 'Users',
- info: 'Per user statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user.<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning childs continiously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited childs of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealisting utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
+ info: 'Per user statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user.<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning children continuously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited children of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealistic utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
height: 1.5
},
'groups': {
title: 'User Groups',
- info: 'Per user group statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user group.<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning childs continiously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited childs of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealisting utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
+ info: 'Per user group statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user group.<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning children continuously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited children of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealistic utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
height: 1.5
},
},
'netfilter.synproxy': {
- title: 'Anti-DDoS Protection',
- info: 'Anti-DDoS Protection performance monitoring read from <code>/proc/net/stat/synproxy</code>. <a href="https://github.com/firehol/firehol/wiki/Working-with-SYNPROXY" target="_blank">SYNPROXY</a> is a TCP SYN packets proxy. It is used to protect any TCP server (like a web server) from SYN floods and similar DDoS attacks. It is a netfilter module, in the Linux kernel (since version 3.12). It is optimized to handle millions of packets per second utilizing all CPUs available without any concurrency locking between the connections. It can be used for any kind of TCP traffic (even encrypted), since it does not interfere with the content itself.'
+ title: 'DDoS Protection',
+ info: 'DDoS Protection performance monitoring read from <code>/proc/net/stat/synproxy</code>. <a href="https://github.com/firehol/firehol/wiki/Working-with-SYNPROXY" target="_blank">SYNPROXY</a> is a TCP SYN packets proxy. It is used to protect any TCP server (like a web server) from SYN floods and similar DDoS attacks. It is a netfilter module, in the Linux kernel (since version 3.12). It is optimized to handle millions of packets per second utilizing all CPUs available without any concurrency locking between the connections. It can be used for any kind of TCP traffic (even encrypted), since it does not interfere with the content itself.'
}
};
'system.idlejitter': {
colors: '#5555AA',
- info: 'Idle jitter is calculated by netdata. A thread is spawned that requests to sleep for a few microseconds. When the system wakes it up, it measures how many microseconds have passed. The difference between the requested and the actual duration of the sleep, is the <b>idle jitter</b>. This number is useful in realtime environments, where CPU jitter can affect the quality of the service (like VoIP media gateways).'
+ info: 'Idle jitter is calculated by netdata. A thread is spawned that requests to sleep for a few microseconds. When the system wakes it up, it measures how many microseconds have passed. The difference between the requested and the actual duration of the sleep, is the <b>idle jitter</b>. This number is useful in real-time environments, where CPU jitter can affect the quality of the service (like VoIP media gateways).'
},
'system.ipv4': {
case 'tc':
chart.menu = tmp;
- // find the interface name from the name
- if(typeof options.submenu_names[chart.family] === 'undefined' || options.submenu_names[chart.family] === chart.family)
- options.submenu_names[chart.family] = chart.name.split('.')[1].split('_')[0];
+ // find a name for this device from fireqos info
+ // we strip '_(in|out)' or '(in|out)_'
+ if(typeof options.submenu_names[chart.family] === 'undefined' || options.submenu_names[chart.family] === chart.family) {
+ var n = chart.name.split('.')[1];
+ if(n.endsWith('_in'))
+ options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_in'));
+ else if(n.endsWith('_out'))
+ options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_out'));
+ else if(n.startsWith('in_'))
+ options.submenu_names[chart.family] = n.slice(3, n.length);
+ else if(n.startsWith('out_'))
+ options.submenu_names[chart.family] = n.slice(4, n.length);
+ }
// increase the priority of IFB devices
+ // to have inbound appear before outbound
if(chart.id.match(/.*-ifb$/))
chart.priority--;
/* activate bootstrap sidebar (affix) */
$('#sidebar').affix({
offset: {
- top: (document.location.hostname === demo_hostname)?150:0,
+ top: (isdemo())?150:0,
bottom: 0
}
});
location.reload();
});
- if(document.location.hostname === demo_hostname) {
+ if(isdemo()) {
setTimeout(function() {
$('#welcomeModal').modal();
}, 1000);
type: number
description: 'The update frequency of this chart, in seconds. One value every this amount of time is kept in the round robin database.'
dimensions:
- description: 'The dimensions of the chart.'
type: object
description: 'An object containing all the chart dimensions available for the chart. This is used as an indexed array. The key of the object the id of the dimension.'
properties: