src/web_client.h
src/web_server.c
src/web_server.h
- )
+ src/locks.h)
set(APPS_PLUGIN_SOURCE_FILES
src/appconfig.c
.eslintignore \
.eslintrc \
.travis \
- m4/ax_check_enable_debug.m4 \
- m4/ax_c_statement_expressions.m4 \
+ m4/jemalloc.m4 \
+ m4/ax_c___atomic.m4 \
+ m4/ax_check_enable_debug.m4 \
+ m4/ax_c_mallinfo.m4 \
+ m4/ax_gcc_func_attribute.m4 \
+ m4/ax_check_compile_flag.m4 \
+ m4/ax_c_statement_expressions.m4 \
+ m4/ax_pthread.m4 \
+ m4/ax_c_lto.m4 \
+ m4/ax_c_mallopt.m4 \
+ m4/tcmalloc.m4 \
+ m4/ax_c__generic.m4 \
autogen.sh \
README.md \
LICENSE.md \
dist_noinst_DATA= \
diagrams/config.puml \
diagrams/registry.puml \
+ diagrams/netdata-for-ephemeral-nodes.xml \
+ diagrams/netdata-proxies-example.xml \
configs.signatures \
Dockerfile \
netdata.spec \
-# netdata [![Build Status](https://travis-ci.org/firehol/netdata.svg?branch=master)](https://travis-ci.org/firehol/netdata) [![Coverity Scan Build Status](https://scan.coverity.com/projects/9140/badge.svg)](https://scan.coverity.com/projects/firehol-netdata) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a994873f30d045b9b4b83606c3eb3498)](https://www.codacy.com/app/netdata/netdata?utm_source=github.com&utm_medium=referral&utm_content=firehol/netdata&utm_campaign=Badge_Grade) [![Code Climate](https://codeclimate.com/github/firehol/netdata/badges/gpa.svg)](https://codeclimate.com/github/firehol/netdata) [![Docker Pulls](https://img.shields.io/docker/pulls/titpetric/netdata.svg)](https://hub.docker.com/r/titpetric/netdata/) [![Twitter Follow](https://img.shields.io/twitter/follow/linuxnetdata.svg?style=social&label=netdata%20on%20twitter)](https://twitter.com/linuxnetdata)
+# netdata [![Build Status](https://travis-ci.org/firehol/netdata.svg?branch=master)](https://travis-ci.org/firehol/netdata) [![Coverity Scan Build Status](https://scan.coverity.com/projects/9140/badge.svg)](https://scan.coverity.com/projects/firehol-netdata) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a994873f30d045b9b4b83606c3eb3498)](https://www.codacy.com/app/netdata/netdata?utm_source=github.com&utm_medium=referral&utm_content=firehol/netdata&utm_campaign=Badge_Grade) [![Code Climate](https://codeclimate.com/github/firehol/netdata/badges/gpa.svg)](https://codeclimate.com/github/firehol/netdata)
> *New to netdata? Here is a live demo: [http://my-netdata.io](http://my-netdata.io)*
**netdata** is a system for **distributed real-time performance and health monitoring**.
(**physical** & **virtual** servers, **containers**, **IoT** devices), without
disrupting their core function._
+netdata runs on **Linux**, **FreeBSD**, and **MacOS**.
+
+[![Twitter Follow](https://img.shields.io/twitter/follow/linuxnetdata.svg?style=social&label=New%20-%20stay%20in%20touch%20-%20follow%20netdata%20on%20twitter)](https://twitter.com/linuxnetdata)
+
---
## User base
*Since May 16th 2016 (the date the [global public netdata registry](https://github.com/firehol/netdata/wiki/mynetdata-menu-item) was released):*<br/>
-[![User Base](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=persons&label=user%20base&units=null&value_color=blue&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Monitored Servers](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=machines&label=servers%20monitored&units=null&value_color=orange&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Sessions Served](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_sessions&label=sessions%20served&units=null&value_color=yellowgreen&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry)
+[![User Base](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=persons&label=user%20base&units=null&value_color=blue&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Monitored Servers](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=machines&label=servers%20monitored&units=null&value_color=orange&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Sessions Served](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_sessions&label=sessions%20served&units=null&value_color=yellowgreen&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Docker Pulls](https://img.shields.io/docker/pulls/titpetric/netdata.svg)](https://hub.docker.com/r/titpetric/netdata/)
*in the last 24 hours:*<br/>
[![New Users Today](http://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=persons&after=-86400&options=unaligned&group=incremental-sum&label=new%20users%20today&units=null&value_color=blue&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![New Machines Today](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_entries&dimensions=machines&group=incremental-sum&after=-86400&options=unaligned&label=servers%20added%20today&units=null&value_color=orange&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry) [![Sessions Today](https://registry.my-netdata.io/api/v1/badge.svg?chart=netdata.registry_sessions&after=-86400&group=incremental-sum&options=unaligned&label=sessions%20served%20today&units=null&value_color=yellowgreen&precision=0&v42)](https://registry.my-netdata.io/#menu_netdata_submenu_registry)
with just 1% CPU utilization of a single core, a few MB of RAM and no disk I/O at all
- **Sophisticated alarming**<br/>
+ hundreds of alarms, **out of the box**!<br/>
supports dynamic thresholds, hysteresis, alarm templates,
multiple role-based notification methods (such as email, slack.com,
pushover.net, pushbullet.com, telegram.org, twilio.com, messagebird.com)
- **scales to infinity**<br/>
requiring minimal central resources
- - **back-ends supported**<br/>
- can archive its metrics on `graphite` or `opentsdb`, in the same or lower detail
+ - **several operating modes**<br/>
+ autonomous host monitoring, headless data collector, forwarding proxy, store and forward proxy, central multi-host monitoring, in all possible configurations.
+ Each node may have different metrics retention policy and run with or without health monitoring.
+
+ - **time-series back-ends supported**<br/>
+ can archive its metrics on `graphite`, `opentsdb`, `prometheus`, json document DBs, in the same or lower detail
(lower: to prevent it from congesting these servers due to the amount of data collected)
![netdata](https://cloud.githubusercontent.com/assets/2662304/14092712/93b039ea-f551-11e5-822c-beadbf2b2a2e.gif)
## What does it monitor?
-netdata monitors several thousands of metrics per device.
+netdata collects several thousands of metrics per device.
All these metrics are collected and visualized in real-time.
> _Almost all metrics are auto-detected, without any configuration._
This is a list of what it currently monitors:
- **CPU**<br/>
- usage, interrupts, softirqs, frequency, total and per core
+ usage, interrupts, softirqs, frequency, total and per core, CPU states
- **Memory**<br/>
RAM, swap and kernel memory usage, KSM (Kernel Samepage Merging), NUMA
- **Disks**<br/>
- per disk: I/O, operations, backlog, utilization, space
+ per disk: I/O, operations, backlog, utilization, space, software RAID (md)
![sda](https://cloud.githubusercontent.com/assets/2662304/14093195/c882bbf4-f554-11e5-8863-1788d643d2c0.gif)
- **Tomcat**<br/>
accesses, threads, free memory, volume
+- **web server log files**<br/>
+ extracting in real-time, web server performance metrics and applying several health checks
+
- **mySQL databases**<br/>
multiple servers, each showing: bandwidth, queries/s, handlers, locks, issues,
tmp operations, connections, binlog metrics, threads, innodb metrics, and more
- **Redis databases**<br/>
multiple servers, each showing: operations, hit rate, memory, keys, clients, slaves
+- **mongodb**<br/>
+ operations, clients, transactions, cursors, connections, asserts, locks, etc
+
- **memcached databases**<br/>
multiple servers, each showing: bandwidth, connections, items
+- **elasticsearch**<br/>
+ search and index performance, latency, timings, cluster statistics, threads statistics, etc
+
- **ISC Bind name servers**<br/>
multiple servers, each showing: clients, requests, queries, updates, failures and several per view metrics
+- **NSD name servers**<br/>
+ queries, zones, protocols, query types, transfers, etc.
+
- **Postfix email servers**<br/>
message queue (entries, size)
- **Dovecot** POP3/IMAP servers<br/>
+- **ISC dhcpd**<br/>
+ pools utilization, leases, etc.
+
- **IPFS**<br/>
bandwidth, peers
- **Squid proxy servers**<br/>
multiple servers, each showing: clients bandwidth and requests, servers bandwidth and requests
+- **HAproxy**<br/>
+ bandwidth, sessions, backends, etc
+
+- **varnish**<br/>
+ threads, sessions, hits, objects, backends, etc
+
+- **OpenVPN**<br/>
+ status per tunnel
+
- **Hardware sensors**<br/>
- temperature, voltage, fans, power, humidity
+ `lm_sensors` and `IPMI`: temperature, voltage, fans, power, humidity
- **NUT and APC UPSes**<br/>
load, charge, battery voltage, temperature, utility metrics, output metrics
- **hddtemp**<br/>
disk temperatures
+- **smartd**<br/>
+ disk S.M.A.R.T. values
+
- **SNMP devices**<br/>
can be monitored too (although you will need to configure these)
python.d/mongodb.conf \
python.d/mysql.conf \
python.d/nginx.conf \
+ python.d/nsd.conf \
python.d/ovpn_status_log.conf \
python.d/phpfpm.conf \
python.d/postfix.conf \
--- /dev/null
+# netdata python.d.plugin configuration for nsd
+#
+# This file is in YaML format. Generally the format is:
+#
+# name: value
+#
+# There are 2 sections:
+# - global variables
+# - one or more JOBS
+#
+# JOBS allow you to collect values from multiple sources.
+# Each source will have its own set of charts.
+#
+# JOB parameters have to be indented (using spaces only, example below).
+
+# ----------------------------------------------------------------------
+# Global Variables
+# These variables set the defaults for all JOBs, however each JOB
+# may define its own, overriding the defaults.
+
+# update_every sets the default data collection frequency.
+# If unset, the python.d.plugin default is used.
+# nsd-control is slow, so once every 30 seconds
+# update_every: 30
+
+# priority controls the order of charts at the netdata dashboard.
+# Lower numbers move the charts towards the top of the page.
+# If unset, the default for python.d.plugin is used.
+# priority: 60000
+
+# retries sets the number of retries to be made in case of failures.
+# If unset, the default for python.d.plugin is used.
+# Attempts to restore the service are made once every update_every
+# and only if the module has collected values in the past.
+# retries: 5
+
+# ----------------------------------------------------------------------
+# JOBS (data collection sources)
+#
+# The default JOBS share the same *name*. JOBS with the same name
+# are mutually exclusive. Only one of them will be allowed running at
+# any time. This allows autodetection to try several alternatives and
+# pick the one that works.
+#
+# Any number of jobs is supported.
+#
+# All python.d.plugin JOBS (for all its modules) support a set of
+# predefined parameters. These are:
+#
+# job_name:
+# name: myname # the JOB's name as it will appear at the
+# # dashboard (by default is the job_name)
+# # JOBs sharing a name are mutually exclusive
+# update_every: 1 # the JOB's data collection frequency
+# priority: 60000 # the JOB's order on the dashboard
+# retries: 5 # the JOB's number of restoration attempts
+#
+# Additionally to the above, nsd also supports the following:
+#
+# command: 'nsd-control stats_noreset' # the command to run
+#
+
+# ----------------------------------------------------------------------
+# IMPORTANT Information
+#
+# Netdata must have permissions to run `nsd-control stats_noreset` command
+#
+# - Example-1 (use "sudo")
+# 1. sudoers (e.g. visudo -f /etc/sudoers.d/netdata)
+# Defaults:netdata !requiretty
+# netdata ALL=(ALL) NOPASSWD: /usr/sbin/nsd-control stats_noreset
+# 2. etc/netdata/python.d/nsd.conf
+# local:
+# update_every: 30
+# command: 'sudo /usr/sbin/nsd-control stats_noreset'
+#
+# - Example-2 (add "netdata" user to "nsd" group)
+# usermod -aG nsd netdata
+#
+
+# ----------------------------------------------------------------------
+# AUTO-DETECTION JOBS
+
+local:
+ update_every: 30
+ command: 'nsd-control stats_noreset'
# You can generate API keys, with the linux command: uuidgen
#
# -----------------------------------------------------------------------------
-# 1. SLAVE NETDATA - THE ONE THAT WILL BE SENDING METRICS
+# 1. ON SLAVE NETDATA - THE ONE THAT WILL BE SENDING METRICS
[stream]
+ # Enable this on slaves, to have them send metrics.
enabled = no
- # where to send metrics to?
- # A space separated list of IP:PORT is accepted. The first available will
- # get the metrics.
- # IPv6 addresses should be [IP]:PORT
+ # The destination to send metrics to.
+ # A space separated list of:
+ # [PROTOCOL:]HOST[%INTERFACE][:PORT]
+ # The first available will get the metrics.
+ # PROTOCOL = tcp or udp (only tcp is supported by masters)
+ # HOST = an IPv4, IPv6 IP, or a hostname.
+ # IPv6 IPs should be given with brackets [ip:address]
+ # INTERFACE = the network interface to use
+ # PORT = the port number or service name (/etc/services)
+ # This communication is not HTTP (cannot be proxied by web proxies).
destination =
# The API_KEY to use (as the sender)
api key =
- # other options (uncomment and set)
+ # The timeout to connect and send metrics
+ timeout seconds = 60
- # timeout seconds = 60
- # default port = 19999
- # buffer size bytes = 1048576
- # reconnect delay seconds = 5
- # initial clock resync iterations = 60
- # free orphan hosts after seconds = 3600
+ # If the destination line above does specify a port, use this
+ default port = 19999
+
+ # The buffer to use for sending metrics.
+ # 1MB by default is good for 2-3 seconds of data, so increase this
+ # if you expect latencies.
+ buffer size bytes = 1048576
+
+ # If the connection fails, or it disconnects,
+ # retry after that many seconds.
+ reconnect delay seconds = 5
+
+ # Attempt to sync the clock the of the master with the clock of the
+ # slave for that many iterations, when starting.
+ initial clock resync iterations = 60
# -----------------------------------------------------------------------------
-# 2. MASTER NETDATA - THE ONE THAT WILL BE RECEIVING METRICS
+# 2. ON MASTER NETDATA - THE ONE THAT WILL BE RECEIVING METRICS
#
# You can have one API key per slave, or the same API key for all slaves.
#
# -----------------------------------------------------------------------------
+# 3. ON MASTER NETDATA - THE ONE THAT WILL BE RECEIVING METRICS
+#
+# THIS IS OPTIONAL - YOU DON'T NEED IT BY DEFAULT
+# It only exists to give you finer control of the master settings for each
+# slave host, when the same API key is used by many netdata slaves / proxies.
+#
# Each netdata has a unique GUID - generated the first time netdata starts.
# You can find it at /var/lib/netdata/registry/netdata.public.unique.id
-# The host sending data will have one. If it is static and you can find it,
+# The host sending data will have one. If the host is not ephemeral,
# you can give settings for each specific host here.
[MACHINE_GUID]
# enable this host: yes | no
+ # When disabled, the master will not receive metrics for this host.
# THIS IS NOT A SECURITY MECHANISM - AN ATTACKER CAN SET ANY OTHER GUID.
# Use only the API key for security.
enabled = no
['573398335c0c71c075fa57f702bce287']='health.d/disks.conf'
['5829812db29598db5857c9f433e96fef']='python.d/apache.conf'
['58e835b7176865ec5a6f59f7aba832bf']='health.d/named.conf'
+ ['598f9814966a9e2fe48e8218151d3fa6']='stream.conf'
['5b917d894bb6a755d59264e9d48e9d56']='fping.conf'
['5bbef0708f5eff4d4a53aaf35fc48a62']='health.d/disks.conf'
['5bf51bb24fb41db9b1e448bd060d3f8c']='apps_groups.conf'
['845023f9b4a526aa0e6493756dbe6034']='health.d/squid.conf'
['846ce94bfeeb90c0dc6a89e8d25f1a68']='health.d/named.conf'
['8490f690d97adacc4e2096df82e7e8a5']='charts.d/cpufreq.conf'
+ ['871bbeea33b83ea9755600b6d574919c']='python.d/web_log.conf'
+ ['87224d2f2b87646f3c0d38cc1eb30112']='python.d/nsd.conf'
['8810140ce9c09af1d18b9602c4003904']='health_alarm_notify.conf'
['88f77865f75c9fb61c97d700bd4561ee']='python.d/mysql.conf'
['8989b5e2f4ef9cd278ef58be0fae4074']='health.d/disks.conf'
['e734c5951a8764d4d9de046dd7cf7407']='health.d/softnet.conf'
['e7bc22a1942cffbd2b1b0cfd119ee328']='health.d/ipfs.conf'
['e8ec8046c7007af6ca3e8c51e62c99f8']='health.d/disks.conf'
+ ['ea1a96c42ad464c354fb250e3408c3e8']='stream.conf'
['eaa7beb935cae9c48a40fb934eb105a7']='health.d/web_log.conf'
['eb5168f0b516bc982aac45e59da6e52e']='health.d/nginx.conf'
['eb748d6fb69d11b0d29c5794657e206c']='health.d/qos.conf'
,
[enable_x86_sse="yes"]
)
+AC_ARG_ENABLE(
+ [lto],
+ [AS_HELP_STRING([--disable-lto], [Link Time Optimizations @<:@default enabled@:>@])],
+ ,
+ [enable_lto="detect"]
+)
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# operating system detection
+AC_MSG_CHECKING([operating system])
case "$host_os" in
freebsd*)
build_target=freebsd
AM_CONDITIONAL([FREEBSD], [test "${build_target}" = "freebsd"])
AM_CONDITIONAL([MACOS], [test "${build_target}" = "macos"])
AM_CONDITIONAL([LINUX], [test "${build_target}" = "linux"])
-
-
-# -----------------------------------------------------------------------------
-# compiler options
-
-AC_ARG_VAR([SSE_CANDIDATE], [C compiler flags for SSE])
-AS_CASE([$host_cpu],
- [i?86], [SSE_CANDIDATE="yes"]
-)
-AC_SUBST([SSE_CANDIDATE])
-if test "${SSE_CANDIDATE}" = "yes" -a "${enable_x86_sse}" = "yes"; then
- opt="-msse2 -mfpmath=sse"
- AX_CHECK_COMPILE_FLAG($opt, [CFLAGS="$CFLAGS $opt"], [])
-fi
-
-if test "${GCC}" = "yes"; then
- AC_DEFINE_UNQUOTED([likely(x)], [__builtin_expect(!!(x), 1)], [gcc branch optimization])
- AC_DEFINE_UNQUOTED([unlikely(x)], [__builtin_expect(!!(x), 0)], [gcc branch optimization])
-else
- AC_DEFINE_UNQUOTED([likely(x)], [(x)], [gcc branch optimization])
- AC_DEFINE_UNQUOTED([unlikely(x)], [(x)], [gcc branch optimization])
-fi
-
-if test "${enable_pedantic}" = "yes"; then
- enable_strict="yes"
- CFLAGS="${CFLAGS} -pedantic -Wall -Wextra -Wno-long-long"
-fi
+AC_MSG_RESULT([${build_target}])
# -----------------------------------------------------------------------------
CC="${PTHREAD_CC}"
-# -----------------------------------------------------------------------------
-# memory allocation library
-
-AC_MSG_CHECKING([for memory allocator])
-TS_CHECK_JEMALLOC
-if test "$has_jemalloc" = "1"; then
- AC_DEFINE([ENABLE_JEMALLOC], [1], [compile and link with jemalloc])
- AC_MSG_RESULT([jemalloc])
-else
- TS_CHECK_TCMALLOC
- if test "$has_tcmalloc" = "1"; then
- AC_DEFINE([ENABLE_TCMALLOC], [1], [compile and link with tcmalloc])
- AC_MSG_RESULT([tcmalloc])
- else
- AC_MSG_RESULT([system])
- AC_C_MALLOPT
- AC_C_MALLINFO
- fi
-fi
-
-
# -----------------------------------------------------------------------------
# libm
OPTIONAL_UUID_LIBS="${UUID_LIBS}"
+# -----------------------------------------------------------------------------
+# compiler options
+
+AC_ARG_VAR([SSE_CANDIDATE], [C compiler flags for SSE])
+AS_CASE([$host_cpu],
+ [i?86], [SSE_CANDIDATE="yes"]
+)
+AC_SUBST([SSE_CANDIDATE])
+if test "${SSE_CANDIDATE}" = "yes" -a "${enable_x86_sse}" = "yes"; then
+ opt="-msse2 -mfpmath=sse"
+ AX_CHECK_COMPILE_FLAG(${opt}, [CFLAGS="${CFLAGS} ${opt}"], [])
+fi
+
+if test "${GCC}" = "yes"; then
+ AC_DEFINE_UNQUOTED([likely(x)], [__builtin_expect(!!(x), 1)], [gcc branch optimization])
+ AC_DEFINE_UNQUOTED([unlikely(x)], [__builtin_expect(!!(x), 0)], [gcc branch optimization])
+else
+ AC_DEFINE_UNQUOTED([likely(x)], [(x)], [gcc branch optimization])
+ AC_DEFINE_UNQUOTED([unlikely(x)], [(x)], [gcc branch optimization])
+fi
+
+if test "${enable_pedantic}" = "yes"; then
+ enable_strict="yes"
+ CFLAGS="${CFLAGS} -pedantic -Wall -Wextra -Wno-long-long"
+fi
+
+
+# -----------------------------------------------------------------------------
+# memory allocation library
+
+AC_MSG_CHECKING([for memory allocator])
+TS_CHECK_JEMALLOC
+if test "$has_jemalloc" = "1"; then
+ AC_DEFINE([ENABLE_JEMALLOC], [1], [compile and link with jemalloc])
+ AC_MSG_RESULT([jemalloc])
+else
+ TS_CHECK_TCMALLOC
+ if test "$has_tcmalloc" = "1"; then
+ AC_DEFINE([ENABLE_TCMALLOC], [1], [compile and link with tcmalloc])
+ AC_MSG_RESULT([tcmalloc])
+ else
+ AC_MSG_RESULT([system])
+ AC_C_MALLOPT
+ AC_C_MALLINFO
+ fi
+fi
+
+
# -----------------------------------------------------------------------------
# libcap
AM_CONDITIONAL([ENABLE_PLUGIN_NFACCT], [test "${enable_plugin_nfacct}" = "yes"])
+# -----------------------------------------------------------------------------
+# Link-Time-Optimization
+
+if test "${enable_lto}" != "no"; then
+ opt="-flto"
+ AX_CHECK_COMPILE_FLAG(${opt}, [have_lto=yes], [have_lto=no])
+fi
+if test "${have_lto}" = "yes"; then
+ oCFLAGS="${CFLAGS}"
+ CFLAGS="${CFLAGS} -flto ${OPTIONAL_MATH_CLFAGS} ${OPTIONAL_NFACCT_CLFAGS} ${OPTIONAL_ZLIB_CLFAGS} ${OPTIONAL_UUID_CLFAGS} ${OPTIONAL_LIBCAP_CFLAGS} ${OPTIONAL_IPMIMONITORING_CFLAGS}"
+ ac_cv_c_lto_cross_compile="${enable_lto}"
+ test "${ac_cv_c_lto_cross_compile}" != "yes" && ac_cv_c_lto_cross_compile="no"
+ AC_C_LTO
+ CFLAGS="${oCFLAGS}"
+ test "${ac_cv_c_lto}" != "yes" && have_lto="no"
+fi
+test "${enable_lto}" = "yes" -a "${have_lto}" != "yes" && \
+ AC_MSG_ERROR([LTO is required but is not available.])
+AC_MSG_CHECKING([if LTO should be enabled])
+if test "${enable_lto}" != "no" -a "${have_lto}" = "yes"; then
+ enable_lto="yes"
+ CFLAGS="${CFLAGS} -flto"
+else
+ enable_lto="no"
+fi
+AC_MSG_RESULT([${enable_lto}])
+
+
# -----------------------------------------------------------------------------
AC_DEFINE_UNQUOTED([NETDATA_USER], ["${with_user}"], [use this user to drop privileged])
--- /dev/null
+# AC_C_LTO
+# -------------
+# Define HAVE_LTO if -flto works.
+AN_IDENTIFIER([lto], [AC_C_LTO])
+AC_DEFUN([AC_C_LTO],
+[AC_CACHE_CHECK([if -flto builds executables], ac_cv_c_lto,
+[AC_RUN_IFELSE(
+ [AC_LANG_SOURCE(
+ [[#include <stdio.h>
+ int main(int argc, char **argv) {
+ return 0;
+ }
+ ]])],
+ [ac_cv_c_lto=yes],
+ [ac_cv_c_lto=no],
+ [ac_cv_c_lto=${ac_cv_c_lto_cross_compile}])])
+if test "${ac_cv_c_lto}" = "yes"; then
+ AC_DEFINE([HAVE_LTO], 1,
+ [Define to 1 if -flto works.])
+fi
+])# AC_C_LTO
Enable/disable the FreeIPMI plugin.
Default: enable it when libipmimonitoring is available.
+ --enable-lto
+ --disable-lto
+
+ Enable/disable Link-Time-Optimization
+ Default: enabled
+
--zlib-is-really-here
--libs-are-really-here
then
NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --disable-plugin-freeipmi"
shift 1
+ elif [ "$1" = "--enable-lto" ]
+ then
+ NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --enable-lto"
+ shift 1
+ elif [ "$1" = "--disable-lto" ]
+ then
+ NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --disable-lto"
+ shift 1
elif [ "$1" = "--help" -o "$1" = "-h" ]
then
usage
NETDATA_ADDED_TO_VARNISH=0
NETDATA_ADDED_TO_HAPROXY=0
NETDATA_ADDED_TO_ADM=0
+NETDATA_ADDED_TO_NSD=0
if [ ${UID} -eq 0 ]
then
portable_add_group netdata
portable_add_user_to_group varnish netdata && NETDATA_ADDED_TO_VARNISH=1
portable_add_user_to_group haproxy netdata && NETDATA_ADDED_TO_HAPROXY=1
portable_add_user_to_group adm netdata && NETDATA_ADDED_TO_ADM=1
+ portable_add_user_to_group nsd netdata && NETDATA_ADDED_TO_NSD=1
run_ok
else
run_failed "The installer does not run as root."
echo " gpasswd -d netdata adm"
fi
+getent group nsd > /dev/null
+if [ $? -eq 0 -a "${NETDATA_ADDED_TO_NSD}" = "1" ]
+ then
+ echo
+ echo "You may also want to remove the netdata user from the nsd group"
+ echo "by running:"
+ echo " gpasswd -d netdata nsd"
+fi
+
UNINSTALL
chmod 750 netdata-uninstaller.sh
if(__DEBUG === true)
netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + " = " + varbinds[i].value);
- if(varbinds[i].type === net_snmp.ObjectType.OctetString)
+ if(varbinds[i].type === net_snmp.ObjectType.OctetString && service.snmp_oids_index[varbinds[i].oid].type !== 'title')
value = parseFloat(varbinds[i].value) * 1000;
else
value = varbinds[i].value;
value_string="${19}" # friendly value (with units)
old_value_string="${20}" # friendly old value (with units)
+# -----------------------------------------------------------------------------
+# find a suitable hostname to use, if netdata did not supply a hostname
+
+[ -z "${host}" ] && host="${NETDATA_HOSTNAME}"
+[ -z "${host}" ] && host="${NETDATA_REGISTRY_HOSTNAME}"
+[ -z "${host}" ] && host="$(hostname 2>/dev/null)"
+
# -----------------------------------------------------------------------------
# screen statuses we don't need to send a notification
# don't do anything if this is not WARNING, CRITICAL or CLEAR
if [ "${status}" != "WARNING" -a "${status}" != "CRITICAL" -a "${status}" != "CLEAR" ]
then
- info "not sending notification for ${status} on '${chart}.${name}'"
+ info "not sending notification for ${status} of '${host}.${chart}.${name}'"
exit 1
fi
# don't do anything if this is CLEAR, but it was not WARNING or CRITICAL
if [ "${old_status}" != "WARNING" -a "${old_status}" != "CRITICAL" -a "${status}" = "CLEAR" ]
then
- info "not sending notification for ${status} on '${chart}.${name}' (last status was ${old_status})"
+ info "not sending notification for ${status} of '${host}.${chart}.${name}' (last status was ${old_status})"
exit 1
fi
-a "${SEND_PD}" != "YES" \
]
then
- fatal "All notification methods are disabled. Not sending notification to '${roles}' for '${name}' = '${value}' of chart '${chart}' for status '${status}'."
+ fatal "All notification methods are disabled. Not sending notification for host '${host}', chart '${chart}' to '${roles}' for '${name}' = '${value}' for status '${status}'."
fi
-# -----------------------------------------------------------------------------
-# find a suitable hostname to use, if netdata did not supply a hostname
-
-[ -z "${host}" ] && host="${NETDATA_HOSTNAME}"
-[ -z "${host}" ] && host="${NETDATA_REGISTRY_HOSTNAME}"
-[ -z "${host}" ] && host="$(hostname 2>/dev/null)"
-
# -----------------------------------------------------------------------------
# get the date the alarm happened
retval=$?
if [ ${retval} -eq 0 ]
then
- info "sent pagerduty.com notification using service key ${PD_SERVICE_KEY::-26}....: ${d}"
+ info "sent pagerduty.com notification for host ${host} ${chart}.${name} using service key ${PD_SERVICE_KEY::-26}....: ${d}"
sent=$((sent + 1))
else
- error "failed to send pagerduty.com notification using service key ${PD_SERVICE_KEY::-26}.... (error code ${retval}): ${d}"
+ error "failed to send pagerduty.com notification for ${host} ${chart}.${name} using service key ${PD_SERVICE_KEY::-26}.... (error code ${retval}): ${d}"
fi
done
mongodb.chart.py \
mysql.chart.py \
nginx.chart.py \
+ nsd.chart.py \
ovpn_status_log.chart.py \
phpfpm.chart.py \
postfix.chart.py \
---
+# nsd
+
+Module uses the `nsd-control stats_noreset` command to provide `nsd` statistics.
+
+**Requirements:**
+ * Version of `nsd` must be 4.0+
+ * Netdata must have permissions to run `nsd-control stats_noreset`
+
+It produces:
+
+1. **Queries**
+ * queries
+
+2. **Zones**
+ * master
+ * slave
+
+3. **Protocol**
+ * udp
+ * udp6
+ * tcp
+ * tcp6
+
+4. **Query Type**
+ * A
+ * NS
+ * CNAME
+ * SOA
+ * PTR
+ * HINFO
+ * MX
+ * NAPTR
+ * TXT
+ * AAAA
+ * SRV
+ * ANY
+
+5. **Transfer**
+ * NOTIFY
+ * AXFR
+
+6. **Return Code**
+ * NOERROR
+ * FORMERR
+ * SERVFAIL
+ * NXDOMAIN
+ * NOTIMP
+ * REFUSED
+ * YXDOMAIN
+
+
+Configuration is not needed.
+
+---
+
# ovpn_status_log
Module monitor openvpn-status log file.
--- /dev/null
+# -*- coding: utf-8 -*-
+# Description: NSD `nsd-control stats_noreset` netdata python.d module
+# Author: <383c57 at gmail.com>
+
+
+from base import ExecutableService
+import re
+
+# default module values (can be overridden per job in `config`)
+priority = 60000
+retries = 5
+update_every = 30
+
+# charts order (can be overridden if you want less charts, or different order)
+ORDER = ['queries', 'zones', 'protocol', 'type', 'transfer', 'rcode']
+
+CHARTS = {
+ 'queries': {
+ 'options': [
+ None, "queries", 'queries/s', 'queries', 'nsd.queries', 'line'],
+ 'lines': [
+ ['num_queries', 'queries', 'incremental'],]},
+ 'zones': {
+ 'options': [
+ None, "zones", 'zones', 'zones', 'nsd.zones', 'stacked'],
+ 'lines': [
+ ['zone_master', 'master', 'absolute'],
+ ['zone_slave', 'slave', 'absolute'],]},
+ 'protocol': {
+ 'options': [
+ None, "protocol", 'queries/s', 'protocol', 'nsd.protocols', 'stacked'],
+ 'lines': [
+ ['num_udp', 'udp', 'incremental'],
+ ['num_udp6', 'udp6', 'incremental'],
+ ['num_tcp', 'tcp', 'incremental'],
+ ['num_tcp6', 'tcp6', 'incremental'],]},
+ 'type': {
+ 'options': [
+ None, "query type", 'queries/s', 'query type', 'nsd.type', 'stacked'],
+ 'lines': [
+ ['num_type_A', 'A', 'incremental'],
+ ['num_type_NS', 'NS', 'incremental'],
+ ['num_type_CNAME', 'CNAME', 'incremental'],
+ ['num_type_SOA', 'SOA', 'incremental'],
+ ['num_type_PTR', 'PTR', 'incremental'],
+ ['num_type_HINFO', 'HINFO', 'incremental'],
+ ['num_type_MX', 'MX', 'incremental'],
+ ['num_type_NAPTR', 'NAPTR', 'incremental'],
+ ['num_type_TXT', 'TXT', 'incremental'],
+ ['num_type_AAAA', 'AAAA', 'incremental'],
+ ['num_type_SRV', 'SRV', 'incremental'],
+ ['num_type_TYPE255', 'ANY', 'incremental'],]},
+ 'transfer': {
+ 'options': [
+ None, "transfer", 'queries/s', 'transfer', 'nsd.transfer', 'stacked'],
+ 'lines': [
+ ['num_opcode_NOTIFY', 'NOTIFY', 'incremental'],
+ ['num_type_TYPE252', 'AXFR', 'incremental'],]},
+ 'rcode': {
+ 'options': [
+ None, "return code", 'queries/s', 'return code', 'nsd.rcode', 'stacked'],
+ 'lines': [
+ ['num_rcode_NOERROR', 'NOERROR', 'incremental'],
+ ['num_rcode_FORMERR', 'FORMERR', 'incremental'],
+ ['num_rcode_SERVFAIL', 'SERVFAIL', 'incremental'],
+ ['num_rcode_NXDOMAIN', 'NXDOMAIN', 'incremental'],
+ ['num_rcode_NOTIMP', 'NOTIMP', 'incremental'],
+ ['num_rcode_REFUSED', 'REFUSED', 'incremental'],
+ ['num_rcode_YXDOMAIN', 'YXDOMAIN', 'incremental'],]}
+}
+
+
+class Service(ExecutableService):
+ def __init__(self, configuration=None, name=None):
+ ExecutableService.__init__(
+ self, configuration=configuration, name=name)
+ self.command = "nsd-control stats_noreset"
+ self.order = ORDER
+ self.definitions = CHARTS
+ self.regex = re.compile(r'([A-Za-z0-9.]+)=(\d+)')
+
+ def _get_data(self):
+ lines = self._get_raw_data()
+ if not lines:
+ return None
+
+ r = self.regex
+ stats = dict((k.replace('.', '_'), int(v))
+ for k, v in r.findall(''.join(lines)))
+ stats.setdefault('num_opcode_NOTIFY', 0)
+ stats.setdefault('num_type_TYPE252', 0)
+ stats.setdefault('num_type_TYPE255', 0)
+ return stats
self.definitions = CHARTS
def check(self):
- if not self.url.endswith('manager/status?XML=true'):
- self.error('Bad url(%s). Must be http://<ip.address>:<port>/manager/status?XML=true' % self.url)
- return False
-
netloc = urlparse(self.url).netloc.rpartition(':')
if netloc[1] == ':': port = netloc[2]
else: port = 80
endif
netdata_SOURCES = \
- appconfig.c appconfig.h \
- adaptive_resortable_list.c adaptive_resortable_list.h \
- avl.c avl.h \
- backends.c backends.h \
- clocks.c clocks.h \
- common.c common.h \
- daemon.c daemon.h \
- dictionary.c dictionary.h \
- eval.c eval.h \
- global_statistics.c global_statistics.h \
- health.c health.h health_log.c health_config.c health_json.c \
+ adaptive_resortable_list.c \
+ adaptive_resortable_list.h \
+ appconfig.c \
+ appconfig.h \
+ avl.c \
+ avl.h \
+ backends.c \
+ backends.h \
+ clocks.c \
+ clocks.h \
+ common.c \
+ common.h \
+ daemon.c \
+ daemon.h \
+ dictionary.c \
+ dictionary.h \
+ eval.c \
+ eval.h \
+ global_statistics.c \
+ global_statistics.h \
+ health.c \
+ health.h \
+ health_config.c \
+ health_json.c \
+ health_log.c \
inlined.h \
- log.c log.h \
- main.c main.h \
- plugin_checks.c plugin_checks.h \
- plugin_idlejitter.c plugin_idlejitter.h \
- plugin_nfacct.c plugin_nfacct.h \
- plugin_tc.c plugin_tc.h \
- plugins_d.c plugins_d.h \
- popen.c popen.h \
- socket.c socket.h \
- simple_pattern.c simple_pattern.h \
- sys_fs_cgroup.c \
- sys_devices_system_edac_mc.c \
- sys_devices_system_node.c \
- procfile.c procfile.h \
- proc_self_mountinfo.c proc_self_mountinfo.h \
- registry.c registry.h \
- registry_internals.c registry_internals.h \
- registry_url.c registry_url.h \
- registry_person.c registry_person.h \
- registry_machine.c registry_machine.h \
- registry_init.c \
+ locks.h \
+ log.c \
+ log.h \
+ main.c \
+ main.h \
+ plugin_checks.c \
+ plugin_checks.h \
+ plugin_idlejitter.c \
+ plugin_idlejitter.h \
+ plugin_nfacct.c \
+ plugin_nfacct.h \
+ plugin_tc.c \
+ plugin_tc.h \
+ plugins_d.c \
+ plugins_d.h \
+ popen.c \
+ popen.h \
+ proc_self_mountinfo.c \
+ proc_self_mountinfo.h \
+ procfile.c \
+ procfile.h \
+ registry.c \
+ registry.h \
registry_db.c \
+ registry_init.c \
+ registry_internals.c \
+ registry_internals.h \
registry_log.c \
- rrd.c rrd.h \
+ registry_machine.c \
+ registry_machine.h \
+ registry_person.c \
+ registry_person.h \
+ registry_url.c \
+ registry_url.h \
+ rrd.c \
+ rrd.h \
+ rrd2json.c \
+ rrd2json.h \
+ rrd2json_api_old.c \
+ rrd2json_api_old.h \
+ rrdcalc.c \
+ rrdcalctemplate.c \
rrddim.c \
+ rrddimvar.c \
rrdfamily.c \
rrdhost.c \
+ rrdpush.c \
+ rrdpush.h \
rrdset.c \
- rrdcalc.c \
- rrdcalctemplate.c \
- rrdvar.c \
- rrddimvar.c \
rrdsetvar.c \
- rrd2json.c rrd2json.h \
- rrd2json_api_old.c rrd2json_api_old.h \
- rrdpush.c rrdpush.h \
- storage_number.c storage_number.h \
- unit_test.c unit_test.h \
+ rrdvar.c \
+ simple_pattern.c \
+ simple_pattern.h \
+ socket.c \
+ socket.h \
+ storage_number.c \
+ storage_number.h \
+ sys_devices_system_edac_mc.c \
+ sys_devices_system_node.c \
+ sys_fs_cgroup.c \
+ unit_test.c \
+ unit_test.h \
url.c url.h \
- web_api_old.c web_api_old.h \
- web_api_v1.c web_api_v1.h \
- web_buffer.c web_buffer.h \
- web_buffer_svg.c web_buffer_svg.h \
- web_client.c web_client.h \
- web_server.c web_server.h \
+ web_api_old.c \
+ web_api_old.h \
+ web_api_v1.c \
+ web_api_v1.h \
+ web_buffer.c \
+ web_buffer.h \
+ web_buffer_svg.c \
+ web_buffer_svg.h \
+ web_client.c \
+ web_client.h \
+ web_server.c \
+ web_server.h \
$(NULL)
if FREEBSD
netdata_SOURCES += \
- plugin_freebsd.c plugin_freebsd.h \
+ plugin_freebsd.c \
+ plugin_freebsd.h \
freebsd_sysctl.c \
$(NULL)
else
if MACOS
netdata_SOURCES += \
- plugin_macos.c plugin_macos.h \
+ plugin_macos.c \
+ plugin_macos.h \
macos_sysctl.c \
macos_mach_smi.c \
macos_fw.c \
else
netdata_SOURCES += \
ipc.c ipc.h \
- plugin_proc.c plugin_proc.h \
- plugin_proc_diskspace.c plugin_proc_diskspace.h \
+ plugin_proc.c \
+ plugin_proc.h \
+ plugin_proc_diskspace.c \
+ plugin_proc_diskspace.h \
proc_diskstats.c \
proc_interrupts.c \
proc_softirqs.c \
struct config_option *values;
avl_tree_lock values_index;
- pthread_mutex_t mutex; // this locks only the writers, to ensure atomic updates
+ netdata_mutex_t mutex; // this locks only the writers, to ensure atomic updates
// readers are protected using the rwlock in avl_tree_lock
};
struct config netdata_config = {
.sections = NULL,
- .mutex = PTHREAD_MUTEX_INITIALIZER,
+ .mutex = NETDATA_MUTEX_INITIALIZER,
.index = {
{ NULL, appconfig_section_compare },
AVL_LOCK_INITIALIZER
struct config stream_config = {
.sections = NULL,
- .mutex = PTHREAD_MUTEX_INITIALIZER,
+ .mutex = NETDATA_MUTEX_INITIALIZER,
.index = {
{ NULL, appconfig_section_compare },
AVL_LOCK_INITIALIZER
// locking
static inline void appconfig_wrlock(struct config *root) {
- pthread_mutex_lock(&root->mutex);
+ netdata_mutex_lock(&root->mutex);
}
static inline void appconfig_unlock(struct config *root) {
- pthread_mutex_unlock(&root->mutex);
+ netdata_mutex_unlock(&root->mutex);
}
static inline void config_section_wrlock(struct section *co) {
- pthread_mutex_lock(&co->mutex);
+ netdata_mutex_lock(&co->mutex);
}
static inline void config_section_unlock(struct section *co) {
- pthread_mutex_unlock(&co->mutex);
+ netdata_mutex_unlock(&co->mutex);
}
struct config {
struct section *sections;
- pthread_mutex_t mutex;
+ netdata_mutex_t mutex;
avl_tree_lock index;
};
}
}
- if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0) {
+ if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
printf("apps.plugin %s\n", VERSION);
exit(0);
}
"\n"
" This program is a data collector plugin for netdata.\n"
"\n"
- " Valid command line options:\n"
+ " Available command line options:\n"
"\n"
" SECONDS set the data collection frequency\n"
"\n"
" apps_groups.conf\n"
" (default NAME=groups)\n"
"\n"
- " version print program version and exit\n"
+ " version or -v or -V print program version and exit\n"
"\n"
, VERSION
);
void avl_read_lock(avl_tree_lock *t) {
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_lock(&t->mutex);
+ netdata_mutex_lock(&t->mutex);
#else
- pthread_rwlock_rdlock(&t->rwlock);
+ netdata_rwlock_rdlock(&t->rwlock);
#endif
#endif /* AVL_WITHOUT_PTHREADS */
}
void avl_write_lock(avl_tree_lock *t) {
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_lock(&t->mutex);
+ netdata_mutex_lock(&t->mutex);
#else
- pthread_rwlock_wrlock(&t->rwlock);
+ netdata_rwlock_wrlock(&t->rwlock);
#endif
#endif /* AVL_WITHOUT_PTHREADS */
}
void avl_unlock(avl_tree_lock *t) {
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_unlock(&t->mutex);
+ netdata_mutex_unlock(&t->mutex);
#else
- pthread_rwlock_unlock(&t->rwlock);
+ netdata_rwlock_unlock(&t->rwlock);
#endif
#endif /* AVL_WITHOUT_PTHREADS */
}
int lock;
#ifdef AVL_LOCK_WITH_MUTEX
- lock = pthread_mutex_init(&t->mutex, NULL);
+ lock = netdata_mutex_init(&t->mutex, NULL);
#else
- lock = pthread_rwlock_init(&t->rwlock, NULL);
+ lock = netdata_rwlock_init(&t->rwlock);
#endif
if(lock != 0)
// #define AVL_LOCK_WITH_MUTEX 1
#ifdef AVL_LOCK_WITH_MUTEX
-#define AVL_LOCK_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define AVL_LOCK_INITIALIZER NETDATA_MUTEX_INITIALIZER
#else /* AVL_LOCK_WITH_MUTEX */
-#define AVL_LOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
+#define AVL_LOCK_INITIALIZER NETDATA_RWLOCK_INITIALIZER
#endif /* AVL_LOCK_WITH_MUTEX */
#else /* AVL_WITHOUT_PTHREADS */
#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_t mutex;
+ netdata_mutex_t mutex;
#else /* AVL_LOCK_WITH_MUTEX */
- pthread_rwlock_t rwlock;
+ netdata_rwlock_t rwlock;
#endif /* AVL_LOCK_WITH_MUTEX */
#endif /* AVL_WITHOUT_PTHREADS */
} avl_tree_lock;
static inline int now_timeval(clockid_t clk_id, struct timeval *tv) {
struct timespec ts;
- if(unlikely(clock_gettime(clk_id, &ts) == -1))
+
+ if(unlikely(clock_gettime(clk_id, &ts) == -1)) {
+ tv->tv_sec = 0;
+ tv->tv_usec = 0;
return -1;
+ }
+
tv->tv_sec = ts.tv_sec;
tv->tv_usec = (suseconds_t)((ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC);
return 0;
// ----------------------------------------------------------------------------
// netdata include files
-#include "simple_pattern.h"
-#include "avl.h"
#include "clocks.h"
#include "log.h"
+#include "locks.h"
+#include "simple_pattern.h"
+#include "avl.h"
#include "global_statistics.h"
#include "storage_number.h"
#include "web_buffer.h"
static inline void dictionary_read_lock(DICTIONARY *dict) {
if(likely(dict->rwlock)) {
// debug(D_DICTIONARY, "Dictionary READ lock");
- pthread_rwlock_rdlock(dict->rwlock);
+ netdata_rwlock_rdlock(dict->rwlock);
}
}
static inline void dictionary_write_lock(DICTIONARY *dict) {
if(likely(dict->rwlock)) {
// debug(D_DICTIONARY, "Dictionary WRITE lock");
- pthread_rwlock_wrlock(dict->rwlock);
+ netdata_rwlock_wrlock(dict->rwlock);
}
}
static inline void dictionary_unlock(DICTIONARY *dict) {
if(likely(dict->rwlock)) {
// debug(D_DICTIONARY, "Dictionary UNLOCK lock");
- pthread_rwlock_unlock(dict->rwlock);
+ netdata_rwlock_unlock(dict->rwlock);
}
}
dict->stats = callocz(1, sizeof(struct dictionary_stats));
if(!(flags & DICTIONARY_FLAG_SINGLE_THREADED)) {
- dict->rwlock = callocz(1, sizeof(pthread_rwlock_t));
- pthread_rwlock_init(dict->rwlock, NULL);
+ dict->rwlock = callocz(1, sizeof(netdata_rwlock_t));
+ netdata_rwlock_init(dict->rwlock);
}
avl_init(&dict->values_index, name_value_compare);
if(dict->stats)
freez(dict->stats);
- if(dict->rwlock)
+ if(dict->rwlock) {
+ netdata_rwlock_destroy(dict->rwlock);
freez(dict->rwlock);
+ }
freez(dict);
}
uint8_t flags;
struct dictionary_stats *stats;
- pthread_rwlock_t *rwlock;
+ netdata_rwlock_t *rwlock;
} DICTIONARY;
#define DICTIONARY_FLAG_DEFAULT 0x00000000
}
}
- if(strcmp("debug", argv[i]) == 0) {
+ if(strcmp("version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
+ printf("freeipmi.plugin %s\n", VERSION);
+ exit(0);
+ }
+ else if(strcmp("debug", argv[i]) == 0) {
debug = 1;
continue;
}
else if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
fprintf(stderr,
"\n"
- "netdata freeipmi.plugin " VERSION "\n"
- "Usage:\n"
+ " netdata freeipmi.plugin %s\n"
+ " Copyright (C) 2016-2017 Costa Tsaousis <costa@tsaousis.gr>\n"
+ " Released under GNU General Public License v3 or later.\n"
+ " All rights reserved.\n"
+ "\n"
+ " This program is a data collector plugin for netdata.\n"
+ "\n"
+ " Available command line options:\n"
+ "\n"
+ " SECONDS data collection frequency\n"
+ " minimum: %d\n"
+ "\n"
+ " debug enable verbose output\n"
+ " default: disabled\n"
+ "\n"
+ " sel\n"
+ " no-sel enable/disable SEL collection\n"
+ " default: %s\n"
+ "\n"
+ " hostname HOST\n"
+ " username USER\n"
+ " password PASS connect to remote IPMI host\n"
+ " default: local IPMI processor\n"
+ "\n"
+ " sdr-cache-dir PATH directory for SDR cache files\n"
+ " default: %s\n"
+ "\n"
+ " sensor-config-file FILE filename to read sensor configuration\n"
+ " default: %s\n"
+ "\n"
+ " -v\n"
+ " -V\n"
+ " version print version and exit\n"
+ "\n"
+ " Linux kernel module for IPMI is CPU hungry.\n"
+ " On Linux run this to lower kipmiN CPU utilization:\n"
+ " # echo 10 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us\n"
+ "\n"
+ " or create: /etc/modprobe.d/ipmi.conf with these contents:\n"
+ " options ipmi_si kipmid_max_busy_us=10\n"
"\n"
- " freeipmi.plugin [OPTIONS]\n"
+ " For more information:\n"
+ " https://github.com/firehol/netdata/wiki/monitoring-IPMI\n"
"\n"
- "Available options:\n"
- " NUMBER, sets the data collection frequency\n"
- " debug, enables verbose output\n"
- " sel, enable SEL collection (it is on by default)\n"
- " no-sel, disable SEL collection\n"
- " hostname X, sets the remote host to connect to\n"
- " username X, sets the username to authenticate at the remote host\n"
- " password X, sets the password to authenticate at the remote host\n"
- " sdr-cache-dir X, sets the directory to save SDR cache files\n"
- " sensor-config-file X, set the filename to read sensor configuration\n"
+ , VERSION
+ , netdata_update_every
+ , netdata_do_sel?"enabled":"disabled"
+ , sdr_cache_directory?sdr_cache_directory:"system default"
+ , sensor_config_file?sensor_config_file:"system default"
);
exit(1);
}
.compressed_content_size = 0
};
-pthread_mutex_t global_statistics_mutex = PTHREAD_MUTEX_INITIALIZER;
+netdata_mutex_t global_statistics_mutex = NETDATA_MUTEX_INITIALIZER;
inline void global_statistics_lock(void) {
- pthread_mutex_lock(&global_statistics_mutex);
+ netdata_mutex_lock(&global_statistics_mutex);
}
inline void global_statistics_unlock(void) {
- pthread_mutex_unlock(&global_statistics_mutex);
+ netdata_mutex_unlock(&global_statistics_mutex);
}
void finished_web_request_statistics(uint64_t dt,
uint32_t first_waiting = (host->health_log.alarms)?host->health_log.alarms->unique_id:0;
time_t now = now_realtime_sec();
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
ALARM_ENTRY *ae;
for(ae = host->health_log.alarms; ae && ae->unique_id >= stop_at_id ; ae = ae->next) {
// remember this for the next iteration
stop_at_id = first_waiting;
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
if(host->health_log.count <= host->health_log.max)
return;
// cleanup excess entries in the log
- pthread_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
ALARM_ENTRY *last = NULL;
unsigned int count = host->health_log.max * 2 / 3;
host->health_log.count--;
}
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
}
static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run) {
unsigned int count;
unsigned int max;
ALARM_ENTRY *alarms;
- pthread_rwlock_t alarm_log_rwlock;
+ netdata_rwlock_t alarm_log_rwlock;
} ALARM_LOG;
#include "rrd.h"
}
void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after) {
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
buffer_strcat(wb, "[");
buffer_strcat(wb, "\n]\n");
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
}
static inline void health_rrdcalc2json_nolock(RRDHOST *host, BUFFER *wb, RRDCALC *rc) {
size_t line = 0, len = 0;
ssize_t loaded = 0, updated = 0, errored = 0, duplicate = 0;
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
while((s = fgets_trim_len(buf, 65536, fp, &len))) {
host->health_log_entries_written++;
}
}
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
freez(buf);
ae->non_clear_duration += ae->duration;
// link it
- pthread_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
ae->next = host->health_log.alarms;
host->health_log.alarms = ae;
host->health_log.count++;
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
// match previous alarms
- pthread_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
ALARM_ENTRY *t;
for(t = host->health_log.alarms ; t ; t = t->next) {
if(t != ae && t->alarm_id == ae->alarm_id) {
break;
}
}
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
health_alarm_log_save(host, ae);
}
inline void health_alarm_log_free(RRDHOST *host) {
rrdhost_check_wrlock(host);
- pthread_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
ALARM_ENTRY *ae;
while((ae = host->health_log.alarms)) {
health_alarm_log_free_one_nochecks_nounlink(ae);
}
- pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
}
--- /dev/null
+#ifndef NETDATA_LOCKS_H
+#define NETDATA_LOCKS_H
+
+// ----------------------------------------------------------------------------
+// mutex
+
+typedef pthread_mutex_t netdata_mutex_t;
+
+#define NETDATA_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+
+static inline int __netdata_mutex_init(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_init(mutex, NULL);
+ if(unlikely(ret != 0))
+ error("MUTEX_LOCK: failed to initialize (code %d).", ret);
+ return ret;
+}
+
+static inline int __netdata_mutex_lock(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_lock(mutex);
+ if(unlikely(ret != 0))
+ error("MUTEX_LOCK: failed to get lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_mutex_trylock(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_trylock(mutex);
+ return ret;
+}
+
+static inline int __netdata_mutex_unlock(netdata_mutex_t *mutex) {
+ int ret = pthread_mutex_unlock(mutex);
+ if(unlikely(ret != 0))
+ error("MUTEX_LOCK: failed to unlock (code %d).", ret);
+ return ret;
+}
+
+#ifdef NETDATA_INTERNAL_CHECKS
+
+static inline int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_init(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_init(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_mutex_lock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_lock(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_lock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_mutex_trylock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_trylock(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_trylock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_mutex_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) from %lu@%s, %s()", mutex, line, file, function);
+ }
+
+ int ret = __netdata_mutex_unlock(mutex);
+
+ debug(D_LOCKS, "MUTEX_LOCK: netdata_mutex_unlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", mutex, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+#define netdata_mutex_init(mutex) netdata_mutex_init_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+#define netdata_mutex_lock(mutex) netdata_mutex_lock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+#define netdata_mutex_trylock(mutex) netdata_mutex_trylock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+#define netdata_mutex_unlock(mutex) netdata_mutex_unlock_debug(__FILE__, __FUNCTION__, __LINE__, mutex)
+
+#else // !NETDATA_INTERNAL_CHECKS
+
+#define netdata_mutex_init(mutex) __netdata_mutex_init(mutex)
+#define netdata_mutex_lock(mutex) __netdata_mutex_lock(mutex)
+#define netdata_mutex_trylock(mutex) __netdata_mutex_trylock(mutex)
+#define netdata_mutex_unlock(mutex) __netdata_mutex_unlock(mutex)
+
+#endif // NETDATA_INTERNAL_CHECKS
+
+
+// ----------------------------------------------------------------------------
+// r/w lock
+
+typedef pthread_rwlock_t netdata_rwlock_t;
+
+#define NETDATA_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
+
+static inline int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_destroy(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to destroy lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_init(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_init(rwlock, NULL);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to initialize lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_rdlock(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to obtain read lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_wrlock(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to obtain write lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_unlock(rwlock);
+ if(unlikely(ret != 0))
+ error("RW_LOCK: failed to release lock (code %d)", ret);
+ return ret;
+}
+
+static inline int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_tryrdlock(rwlock);
+ return ret;
+}
+
+static inline int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) {
+ int ret = pthread_rwlock_trywrlock(rwlock);
+ return ret;
+}
+
+
+#ifdef NETDATA_INTERNAL_CHECKS
+
+static inline int netdata_rwlock_destroy_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_destroy(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_destroy(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_init(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_init(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_rdlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_rdlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_wrlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_wrlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_unlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_unlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_tryrdlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_tryrdlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+static inline int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock) {
+ usec_t start = 0;
+
+ if(unlikely(debug_flags & D_LOCKS)) {
+ start = now_boottime_usec();
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) from %lu@%s, %s()", rwlock, line, file, function);
+ }
+
+ int ret = __netdata_rwlock_trywrlock(rwlock);
+
+ debug(D_LOCKS, "RW_LOCK: netdata_rwlock_trywrlock(0x%p) = %d in %llu usec, from %lu@%s, %s()", rwlock, ret, now_boottime_usec() - start, line, file, function);
+
+ return ret;
+}
+
+#define netdata_rwlock_destroy(rwlock) netdata_rwlock_destroy_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_init(rwlock) netdata_rwlock_init_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_rdlock(rwlock) netdata_rwlock_rdlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_wrlock(rwlock) netdata_rwlock_wrlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_unlock(rwlock) netdata_rwlock_unlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_tryrdlock(rwlock) netdata_rwlock_tryrdlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+#define netdata_rwlock_trywrlock(rwlock) netdata_rwlock_trywrlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
+
+#else // !NETDATA_INTERNAL_CHECKS
+
+#define netdata_rwlock_destroy(rwlock) __netdata_rwlock_destroy(rwlock)
+#define netdata_rwlock_init(rwlock) __netdata_rwlock_init(rwlock)
+#define netdata_rwlock_rdlock(rwlock) __netdata_rwlock_rdlock(rwlock)
+#define netdata_rwlock_wrlock(rwlock) __netdata_rwlock_wrlock(rwlock)
+#define netdata_rwlock_unlock(rwlock) __netdata_rwlock_unlock(rwlock)
+#define netdata_rwlock_tryrdlock(rwlock) __netdata_rwlock_tryrdlock(rwlock)
+#define netdata_rwlock_trywrlock(rwlock) __netdata_rwlock_trywrlock(rwlock)
+
+#endif // NETDATA_INTERNAL_CHECKS
+
+#endif //NETDATA_LOCKS_H
#define D_HEALTH 0x0000000000800000
#define D_CONNECT_TO 0x0000000001000000
#define D_RRDHOST 0x0000000002000000
+#define D_LOCKS 0x0000000004000000
#define D_SYSTEM 0x8000000000000000
//#define DEBUG (D_WEB_CLIENT_ACCESS|D_LISTENER|D_RRD_STATS)
{ 't', "The internal clock of netdata.", "seconds", "1"},
{ 'u', "Run as user.", "username", "netdata"},
{ 'v', "Print netdata version and exit.", NULL, NULL},
+ { 'V', "Print netdata version and exit.", NULL, NULL},
{ 'W', "See Advanced options below.", "options", NULL},
};
config_set(CONFIG_SECTION_GLOBAL, "run as user", optarg);
break;
case 'v':
+ case 'V':
printf("%s %s\n", program_name, program_version);
return 0;
case 'W':
// REGISTRY concurrency locking
static inline void registry_lock(void) {
- pthread_mutex_lock(®istry.lock);
+ netdata_mutex_lock(®istry.lock);
}
static inline void registry_unlock(void) {
- pthread_mutex_unlock(®istry.lock);
+ netdata_mutex_unlock(®istry.lock);
}
registry.machines_urls_memory = 0;
// initialize locks
- pthread_mutex_init(®istry.lock, NULL);
+ netdata_mutex_init(®istry.lock);
// create dictionaries
registry.persons = dictionary_create(DICTIONARY_FLAGS);
avl_tree registry_urls_root_index;
- pthread_mutex_t lock;
+ netdata_mutex_t lock;
};
extern int regenerate_guid(const char *guid, char *result);
char *cache_dir; // the directory to store dimensions
char cache_filename[FILENAME_MAX+1]; // the filename to store this set
- pthread_rwlock_t rrdset_rwlock; // protects dimensions linked list
+ netdata_rwlock_t rrdset_rwlock; // protects dimensions linked list
size_t counter; // the number of times we added values to this database
size_t counter_done; // the number of times rrdset_done() has been called
};
typedef struct rrdset RRDSET;
-#define rrdset_rdlock(st) pthread_rwlock_rdlock(&((st)->rrdset_rwlock))
-#define rrdset_wrlock(st) pthread_rwlock_wrlock(&((st)->rrdset_rwlock))
-#define rrdset_unlock(st) pthread_rwlock_unlock(&((st)->rrdset_rwlock))
+#define rrdset_rdlock(st) netdata_rwlock_rdlock(&((st)->rrdset_rwlock))
+#define rrdset_wrlock(st) netdata_rwlock_wrlock(&((st)->rrdset_rwlock))
+#define rrdset_unlock(st) netdata_rwlock_unlock(&((st)->rrdset_rwlock))
+
// ----------------------------------------------------------------------------
// these loop macros make sure the linked list is accessed with the right lock
volatile int rrdpush_error_shown:1; // 1 when we have logged a communication error
int rrdpush_socket; // the fd of the socket to the remote host, or -1
pthread_t rrdpush_thread; // the sender thread
- pthread_mutex_t rrdpush_mutex; // exclusive access to rrdpush_buffer
+ netdata_mutex_t rrdpush_mutex; // exclusive access to rrdpush_buffer
int rrdpush_pipe[2]; // collector to sender thread communication
BUFFER *rrdpush_buffer; // collector fills it, sender sends them
// ------------------------------------------------------------------------
// locks
- pthread_rwlock_t rrdhost_rwlock; // lock for this RRDHOST (protects rrdset_root linked list)
+ netdata_rwlock_t rrdhost_rwlock; // lock for this RRDHOST (protects rrdset_root linked list)
avl_tree_lock rrdset_root_index; // the host's charts index (by id)
avl_tree_lock rrdset_root_index_name; // the host's charts index (by name)
typedef struct rrdhost RRDHOST;
extern RRDHOST *localhost;
-#define rrdhost_rdlock(h) pthread_rwlock_rdlock(&((h)->rrdhost_rwlock))
-#define rrdhost_wrlock(h) pthread_rwlock_wrlock(&((h)->rrdhost_rwlock))
-#define rrdhost_unlock(h) pthread_rwlock_unlock(&((h)->rrdhost_rwlock))
+#define rrdhost_rdlock(host) netdata_rwlock_rdlock(&((host)->rrdhost_rwlock))
+#define rrdhost_wrlock(host) netdata_rwlock_wrlock(&((host)->rrdhost_rwlock))
+#define rrdhost_unlock(host) netdata_rwlock_unlock(&((host)->rrdhost_rwlock))
// ----------------------------------------------------------------------------
// these loop macros make sure the linked list is accessed with the right lock
// ----------------------------------------------------------------------------
// global lock for all RRDHOSTs
-extern pthread_rwlock_t rrd_rwlock;
-#define rrd_rdlock() pthread_rwlock_rdlock(&rrd_rwlock)
-#define rrd_wrlock() pthread_rwlock_wrlock(&rrd_rwlock)
-#define rrd_unlock() pthread_rwlock_unlock(&rrd_rwlock)
+extern netdata_rwlock_t rrd_rwlock;
+
+#define rrd_rdlock() netdata_rwlock_rdlock(&rrd_rwlock)
+#define rrd_wrlock() netdata_rwlock_wrlock(&rrd_rwlock)
+#define rrd_unlock() netdata_rwlock_unlock(&rrd_rwlock)
// ----------------------------------------------------------------------------
, char *rrdpush_api_key
);
-#ifdef NETDATA_INTERNAL_CHECKS
-extern void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line);
-extern void rrdhost_check_rdlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line);
-extern void rrdset_check_rdlock_int(RRDSET *st, const char *file, const char *function, const unsigned long line);
-extern void rrdset_check_wrlock_int(RRDSET *st, const char *file, const char *function, const unsigned long line);
-extern void rrd_check_rdlock_int(const char *file, const char *function, const unsigned long line);
-extern void rrd_check_wrlock_int(const char *file, const char *function, const unsigned long line);
-
-#define rrdhost_check_rdlock(host) rrdhost_check_rdlock_int(host, __FILE__, __FUNCTION__, __LINE__)
-#define rrdhost_check_wrlock(host) rrdhost_check_wrlock_int(host, __FILE__, __FUNCTION__, __LINE__)
-#define rrdset_check_rdlock(st) rrdset_check_rdlock_int(st, __FILE__, __FUNCTION__, __LINE__)
-#define rrdset_check_wrlock(st) rrdset_check_wrlock_int(st, __FILE__, __FUNCTION__, __LINE__)
-#define rrd_check_rdlock() rrd_check_rdlock_int(__FILE__, __FUNCTION__, __LINE__)
-#define rrd_check_wrlock() rrd_check_wrlock_int(__FILE__, __FUNCTION__, __LINE__)
+#if defined(NETDATA_INTERNAL_CHECKS) && defined(NETDATA_VERIFY_LOCKS)
+extern void __rrdhost_check_wrlock(RRDHOST *host, const char *file, const char *function, const unsigned long line);
+extern void __rrdhost_check_rdlock(RRDHOST *host, const char *file, const char *function, const unsigned long line);
+extern void __rrdset_check_rdlock(RRDSET *st, const char *file, const char *function, const unsigned long line);
+extern void __rrdset_check_wrlock(RRDSET *st, const char *file, const char *function, const unsigned long line);
+extern void __rrd_check_rdlock(const char *file, const char *function, const unsigned long line);
+extern void __rrd_check_wrlock(const char *file, const char *function, const unsigned long line);
+
+#define rrdhost_check_rdlock(host) __rrdhost_check_rdlock(host, __FILE__, __FUNCTION__, __LINE__)
+#define rrdhost_check_wrlock(host) __rrdhost_check_wrlock(host, __FILE__, __FUNCTION__, __LINE__)
+#define rrdset_check_rdlock(st) __rrdset_check_rdlock(st, __FILE__, __FUNCTION__, __LINE__)
+#define rrdset_check_wrlock(st) __rrdset_check_wrlock(st, __FILE__, __FUNCTION__, __LINE__)
+#define rrd_check_rdlock() __rrd_check_rdlock(__FILE__, __FUNCTION__, __LINE__)
+#define rrd_check_wrlock() __rrd_check_wrlock(__FILE__, __FUNCTION__, __LINE__)
#else
#define rrdhost_check_rdlock(host) (void)0
// ----------------------------------------------------------------------------
+void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, BUFFER *wb) {
+ rrdhost_rdlock(host);
+
+ buffer_strcat(wb, "{");
+
+ size_t chart_counter = 0;
+ size_t dimension_counter = 0;
+
+ // for each chart
+ RRDSET *st;
+ rrdset_foreach_read(st, host) {
+ if(rrdset_is_available_for_viewers(st)) {
+ rrdset_rdlock(st);
+
+ buffer_sprintf(wb, "%s\n"
+ "\t\"%s\": {\n"
+ "\t\t\"name\":\"%s\",\n"
+ "\t\t\"context\":\"%s\",\n"
+ "\t\t\"units\":\"%s\",\n"
+ "\t\t\"last_updated\": %ld,\n"
+ "\t\t\"dimensions\": {"
+ , chart_counter?",":""
+ , st->id
+ , st->name
+ , st->context
+ , st->units
+ , rrdset_last_entry_t(st)
+ );
+
+ chart_counter++;
+ dimension_counter = 0;
+
+ // for each dimension
+ RRDDIM *rd;
+ rrddim_foreach_read(rd, st) {
+ if(rd->collections_counter) {
+
+ buffer_sprintf(wb, "%s\n"
+ "\t\t\t\"%s\": {\n"
+ "\t\t\t\t\"name\": \"%s\",\n"
+ "\t\t\t\t\"value\": "
+ , dimension_counter?",":""
+ , rd->id
+ , rd->name
+ );
+
+ if(isnan(rd->last_stored_value))
+ buffer_strcat(wb, "null");
+ else
+ buffer_sprintf(wb, CALCULATED_NUMBER_FORMAT, rd->last_stored_value);
+
+ buffer_strcat(wb, "\n\t\t\t}");
+
+ dimension_counter++;
+ }
+ }
+
+ buffer_strcat(wb, "\n\t\t}\n\t}");
+ rrdset_unlock(st);
+ }
+ }
+
+ buffer_strcat(wb, "\n}");
+ rrdhost_unlock(host);
+}
+
+// ----------------------------------------------------------------------------
+
// RRDR dimension options
#define RRDR_EMPTY 0x01 // the dimension contains / the value is empty (null)
#define RRDR_RESET 0x02 // the dimension contains / the value is reset
#define ALLMETRICS_FORMAT_SHELL "shell"
#define ALLMETRICS_FORMAT_PROMETHEUS "prometheus"
+#define ALLMETRICS_FORMAT_JSON "json"
#define ALLMETRICS_SHELL 1
#define ALLMETRICS_PROMETHEUS 2
+#define ALLMETRICS_JSON 3
#define GROUP_UNDEFINED 0
#define GROUP_AVERAGE 1
extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb);
extern void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb);
+extern void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, BUFFER *wb);
extern void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, BUFFER *wb);
extern void rrd_stats_api_v1_charts_allmetrics_prometheus(RRDHOST *host, BUFFER *wb);
RRDHOST *localhost = NULL;
size_t rrd_hosts_available = 0;
-pthread_rwlock_t rrd_rwlock = PTHREAD_RWLOCK_INITIALIZER;
+netdata_rwlock_t rrd_rwlock = NETDATA_RWLOCK_INITIALIZER;
time_t rrdset_free_obsolete_time = 3600;
time_t rrdhost_free_orphan_time = 3600;
char *rrdpush_api_key,
int is_localhost
) {
-
debug(D_RRDHOST, "Host '%s': adding with guid '%s'", hostname, guid);
+ rrd_check_wrlock();
+
RRDHOST *host = callocz(1, sizeof(RRDHOST));
host->rrd_update_every = update_every;
host->rrdpush_pipe[1] = -1;
host->rrdpush_socket = -1;
- pthread_mutex_init(&host->rrdpush_mutex, NULL);
- pthread_rwlock_init(&host->rrdhost_rwlock, NULL);
+ netdata_mutex_init(&host->rrdpush_mutex);
+ netdata_rwlock_init(&host->rrdhost_rwlock);
rrdhost_init_hostname(host, hostname);
rrdhost_init_machine_guid(host, guid);
else
host->health_log.max = (unsigned int)n;
- pthread_rwlock_init(&(host->health_log.alarm_log_rwlock), NULL);
+ netdata_rwlock_init(&host->health_log.alarm_log_rwlock);
char filename[FILENAME_MAX + 1];
// ------------------------------------------------------------------------
// link it and add it to the index
- rrd_wrlock();
-
if(is_localhost) {
host->next = localhost;
localhost = host;
}
rrd_hosts_available++;
- rrd_unlock();
return host;
}
) {
debug(D_RRDHOST, "Searching for host '%s' with guid '%s'", hostname, guid);
+ rrd_wrlock();
RRDHOST *host = rrdhost_find_by_guid(guid, 0);
if(!host) {
host = rrdhost_create(
if(strcmp(host->hostname, hostname)) {
char *t = host->hostname;
- char *n = strdupz(hostname);
- host->hostname = n;
+ host->hostname = strdupz(hostname);
+ host->hash_hostname = simple_hash(host->hostname);
freez(t);
}
if(host->rrd_memory_mode != mode)
error("Host '%s' has memory mode '%s', but the wanted one is '%s'.", host->hostname, rrd_memory_mode_name(host->rrd_memory_mode), rrd_memory_mode_name(mode));
}
+ rrd_unlock();
rrdhost_cleanup_orphan(host);
return host;
}
+static inline int rrdhost_should_be_deleted(RRDHOST *host, RRDHOST *protected, time_t now) {
+ if(host != protected
+ && host != localhost
+ && !host->connected_senders
+ && host->senders_disconnected_time
+ && host->senders_disconnected_time + rrdhost_free_orphan_time < now)
+ return 1;
+
+ return 0;
+}
+
void rrdhost_cleanup_orphan(RRDHOST *protected) {
time_t now = now_realtime_sec();
restart_after_removal:
rrdhost_foreach_write(host) {
- if(host != protected
- && host != localhost
- && !host->connected_senders
- && host->senders_disconnected_time + rrdhost_free_orphan_time < now) {
+ if(rrdhost_should_be_deleted(host, protected, now)) {
info("Host '%s' with machine guid '%s' is obsolete - cleaning up.", host->hostname, host->machine_guid);
if(rrdset_flag_check(host, RRDHOST_ORPHAN))
rrdpush_init();
debug(D_RRDHOST, "Initializing localhost with hostname '%s'", hostname);
+ rrd_wrlock();
localhost = rrdhost_create(
hostname
, registry_get_this_machine_guid()
, default_rrdpush_api_key
, 1
);
+ rrd_unlock();
}
// ----------------------------------------------------------------------------
// RRDHOST - lock validations
// there are only used when NETDATA_INTERNAL_CHECKS is set
-void rrdhost_check_rdlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
+void __rrdhost_check_rdlock(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
debug(D_RRDHOST, "Checking read lock on host '%s'", host->hostname);
- int ret = pthread_rwlock_trywrlock(&host->rrdhost_rwlock);
+ int ret = netdata_rwlock_trywrlock(&host->rrdhost_rwlock);
if(ret == 0)
fatal("RRDHOST '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
}
-void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
+void __rrdhost_check_wrlock(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
debug(D_RRDHOST, "Checking write lock on host '%s'", host->hostname);
- int ret = pthread_rwlock_tryrdlock(&host->rrdhost_rwlock);
+ int ret = netdata_rwlock_tryrdlock(&host->rrdhost_rwlock);
if(ret == 0)
fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
}
-void rrd_check_rdlock_int(const char *file, const char *function, const unsigned long line) {
+void __rrd_check_rdlock(const char *file, const char *function, const unsigned long line) {
debug(D_RRDHOST, "Checking read lock on all RRDs");
- int ret = pthread_rwlock_trywrlock(&rrd_rwlock);
+ int ret = netdata_rwlock_trywrlock(&rrd_rwlock);
if(ret == 0)
fatal("RRDs should be read-locked, but it are not, at function %s() at line %lu of file '%s'", function, line, file);
}
-void rrd_check_wrlock_int(const char *file, const char *function, const unsigned long line) {
+void __rrd_check_wrlock(const char *file, const char *function, const unsigned long line) {
debug(D_RRDHOST, "Checking write lock on all RRDs");
- int ret = pthread_rwlock_tryrdlock(&rrd_rwlock);
+ int ret = netdata_rwlock_tryrdlock(&rrd_rwlock);
if(ret == 0)
fatal("RRDs should be write-locked, but it are not, at function %s() at line %lu of file '%s'", function, line, file);
}
freez(host->health_log_filename);
freez(host->hostname);
rrdhost_unlock(host);
+ netdata_rwlock_destroy(&host->health_log.alarm_log_rwlock);
+ netdata_rwlock_destroy(&host->rrdhost_rwlock);
freez(host);
rrd_hosts_available--;
default_rrdpush_enabled = appconfig_get_boolean(&stream_config, CONFIG_SECTION_STREAM, "enabled", default_rrdpush_enabled);
default_rrdpush_destination = appconfig_get(&stream_config, CONFIG_SECTION_STREAM, "destination", "");
default_rrdpush_api_key = appconfig_get(&stream_config, CONFIG_SECTION_STREAM, "api key", "");
- rrdhost_free_orphan_time = appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "free orphan hosts after seconds", rrdhost_free_orphan_time);
+ rrdhost_free_orphan_time = config_get_number(CONFIG_SECTION_GLOBAL, "cleanup orphan hosts after seconds", rrdhost_free_orphan_time);
if(default_rrdpush_enabled && (!default_rrdpush_destination || !*default_rrdpush_destination || !default_rrdpush_api_key || !*default_rrdpush_api_key)) {
error("STREAM [send]: cannot enable sending thread - information is missing.");
// this is for the first iterations of each chart
static unsigned int remote_clock_resync_iterations = 60;
-#define rrdpush_lock(host) pthread_mutex_lock(&((host)->rrdpush_mutex))
-#define rrdpush_unlock(host) pthread_mutex_unlock(&((host)->rrdpush_mutex))
+#define rrdpush_lock(host) netdata_mutex_lock(&((host)->rrdpush_mutex))
+#define rrdpush_unlock(host) netdata_mutex_unlock(&((host)->rrdpush_mutex))
// checks if the current chart definition has been sent
static inline int need_to_send_chart_definition(RRDSET *st) {
#define RRD_DEFAULT_GAP_INTERPOLATIONS 1
-void rrdset_check_rdlock_int(RRDSET *st, const char *file, const char *function, const unsigned long line) {
+void __rrdset_check_rdlock(RRDSET *st, const char *file, const char *function, const unsigned long line) {
debug(D_RRD_CALLS, "Checking read lock on chart '%s'", st->id);
- int ret = pthread_rwlock_trywrlock(&st->rrdset_rwlock);
+ int ret = netdata_rwlock_trywrlock(&st->rrdset_rwlock);
if(ret == 0)
fatal("RRDSET '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", st->id, function, line, file);
}
-void rrdset_check_wrlock_int(RRDSET *st, const char *file, const char *function, const unsigned long line) {
+void __rrdset_check_wrlock(RRDSET *st, const char *file, const char *function, const unsigned long line) {
debug(D_RRD_CALLS, "Checking write lock on chart '%s'", st->id);
- int ret = pthread_rwlock_tryrdlock(&st->rrdset_rwlock);
+ int ret = netdata_rwlock_tryrdlock(&st->rrdset_rwlock);
if(ret == 0)
fatal("RRDSET '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", st->id, function, line, file);
}
// ------------------------------------------------------------------------
// free it
+ netdata_rwlock_destroy(&st->rrdset_rwlock);
+
// free directly allocated members
freez(st->config_section);
// ----------------------------------------------------------------------------
// RRDSET - create a chart
+static inline RRDSET *rrdset_find_on_create(RRDHOST *host, const char *fullid) {
+ RRDSET *st = rrdset_find(host, fullid);
+ if(unlikely(st)) {
+ rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
+ debug(D_RRD_CALLS, "RRDSET '%s', already exists.", fullid);
+ return st;
+ }
+
+ return NULL;
+}
+
RRDSET *rrdset_create(
RRDHOST *host
, const char *type
char fullid[RRD_ID_LENGTH_MAX + 1];
snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
- RRDSET *st = rrdset_find(host, fullid);
+ RRDSET *st = rrdset_find_on_create(host, fullid);
+ if(st) return st;
+
+ rrdhost_wrlock(host);
+
+ st = rrdset_find_on_create(host, fullid);
if(st) {
- rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
- debug(D_RRD_CALLS, "RRDSET '%s', already exists.", fullid);
+ rrdhost_unlock(host);
return st;
}
memset(&st->avlname, 0, sizeof(avl));
memset(&st->variables_root_index, 0, sizeof(avl_tree_lock));
memset(&st->dimensions_index, 0, sizeof(avl_tree_lock));
- memset(&st->rrdset_rwlock, 0, sizeof(pthread_rwlock_t));
+ memset(&st->rrdset_rwlock, 0, sizeof(netdata_rwlock_t));
st->name = NULL;
st->type = NULL;
avl_init_lock(&st->dimensions_index, rrddim_compare);
avl_init_lock(&st->variables_root_index, rrdvar_compare);
- pthread_rwlock_init(&st->rrdset_rwlock, NULL);
- rrdhost_wrlock(host);
+ netdata_rwlock_init(&st->rrdset_rwlock);
if(name && *name) rrdset_set_name(st, name);
else rrdset_set_name(st, id);
RRDDIM *last;
// there is dimension to free
// upgrade our read lock to a write lock
- pthread_rwlock_unlock(&st->rrdset_rwlock);
- pthread_rwlock_wrlock(&st->rrdset_rwlock);
+ rrdset_unlock(st);
+ rrdset_wrlock(st);
for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
// remove it only it is not updated in rrd_delete_unupdated_dimensions seconds
format = ALLMETRICS_SHELL;
else if(!strcmp(value, ALLMETRICS_FORMAT_PROMETHEUS))
format = ALLMETRICS_PROMETHEUS;
+ else if(!strcmp(value, ALLMETRICS_FORMAT_JSON))
+ format = ALLMETRICS_JSON;
else
format = 0;
}
buffer_no_cacheable(w->response.data);
switch(format) {
+ case ALLMETRICS_JSON:
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ rrd_stats_api_v1_charts_allmetrics_json(host, w->response.data);
+ return 200;
+
case ALLMETRICS_SHELL:
w->response.data->contenttype = CT_TEXT_PLAIN;
rrd_stats_api_v1_charts_allmetrics_shell(host, w->response.data);
default:
w->response.data->contenttype = CT_TEXT_PLAIN;
- buffer_strcat(w->response.data, "Which format? Only '" ALLMETRICS_FORMAT_SHELL "' and '" ALLMETRICS_FORMAT_PROMETHEUS "' is currently supported.");
+ buffer_strcat(w->response.data, "Which format? '" ALLMETRICS_FORMAT_SHELL "', '" ALLMETRICS_FORMAT_PROMETHEUS "' and '" ALLMETRICS_FORMAT_JSON "' are currently supported.");
return 400;
}
}
var len, i, url, hostname, icon;
if(options.hosts.length > 1) {
+ // there are mirrored hosts here
+
el += '<li><a href="#" onClick="return false;" style="color: #666;" target="_blank">databases available on this host</a></li>';
a1 += '<li><a href="#" onClick="return false;"><i class="fa fa-info-circle" aria-hidden="true" style="color: #666;"></i></a></li>';
if(base.endsWith("/"))
base = base.substring(0, base.length - 1);
+ var master = options.hosts[0].hostname;
+ var sorted = options.hosts.sort(function(a, b) {
+ if(a.hostname === master) return -1;
+ if(a.hostname === b.hostname) return 0;
+ else if(a.hostname > b.hostname) return 1;
+ return -1;
+ });
+
i = 0;
- len = options.hosts.length;
+ len = sorted.length;
while(len--) {
- hostname = options.hosts[i].hostname;
- if(i == 0) {
+ hostname = sorted[i].hostname;
+ if(hostname == master) {
url = base + "/";
icon = "home";
}