You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bc...@apache.org on 2017/12/04 17:35:32 UTC

[trafficserver] branch master updated: Create system_stats plugin. This will insert system information in to the stats list on a five second interval. Currently it pulls load averages, number of processes, and most of the information from sysfs for each available network device.

This is an automated email from the ASF dual-hosted git repository.

bcall pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 9145d25  Create system_stats plugin. This will insert system information in to the stats list on a five second interval.  Currently it pulls load averages, number of processes, and most of the information from sysfs for each available network device.
9145d25 is described below

commit 9145d255408c3dd395caa855341b7dfc42ba78ba
Author: Evan Zelkowitz <ev...@gmail.com>
AuthorDate: Tue Nov 14 09:30:34 2017 -0700

    Create system_stats plugin. This will insert system information in to
    the stats list on a five second interval.  Currently it pulls load
    averages, number of processes, and most of the information from sysfs
    for each available network device.
---
 doc/admin-guide/plugins/index.en.rst             |   4 +
 doc/admin-guide/plugins/system_stats.en.rst      |  89 ++++++++
 plugins/Makefile.am                              |   1 +
 plugins/experimental/system_stats/Makefile.inc   |  20 ++
 plugins/experimental/system_stats/system_stats.c | 256 +++++++++++++++++++++++
 5 files changed, 370 insertions(+)

diff --git a/doc/admin-guide/plugins/index.en.rst b/doc/admin-guide/plugins/index.en.rst
index b864aed..9081182 100644
--- a/doc/admin-guide/plugins/index.en.rst
+++ b/doc/admin-guide/plugins/index.en.rst
@@ -142,6 +142,7 @@ directory of the |TS| source tree. Experimental plugins can be compiled by passi
    Signed URLs <url_sig.en>
    SSL Headers <sslheaders.en>
    Stale While Revalidate <stale_while_revalidate.en>
+   System Statistics <system_stats.en>
    TS Lua <ts_lua.en>
    WebP Transform <webp_transform.en>
 
@@ -206,6 +207,9 @@ directory of the |TS| source tree. Experimental plugins can be compiled by passi
 
    Refresh content asynchronously while serving stale data.
 
+:doc:`System Stats <system_stats.en>`
+    Inserts system statistics in to the stats list
+
 :doc:`TS Lua <ts_lua.en>`
    Allows plugins to be written in Lua instead of C code.
 
diff --git a/doc/admin-guide/plugins/system_stats.en.rst b/doc/admin-guide/plugins/system_stats.en.rst
new file mode 100644
index 0000000..d71460f
--- /dev/null
+++ b/doc/admin-guide/plugins/system_stats.en.rst
@@ -0,0 +1,89 @@
+.. Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+   under the License.
+
+.. include:: ../../common.defs
+
+.. _admin-plugins-system_stats:
+
+System Stats Plugin
+********************
+
+Purpose
+=======
+
+This plugin inserts system statistics in to the stats list that can then be
+retrieved either with stats_over_http or any other method using the management port.
+These can be used to diagnose issues like excessive load or networking performance.
+
+Installation
+============
+
+To enable this plugin, build with experimental plugin support add to the :file:`plugin.config` file::
+
+    system_stats.so
+
+Caveats
+=======
+
+This plugin depends greatly on the sysfs interface so it is mostly useful only for Linux hosts, however
+it will build for other hosts.
+
+Examples
+========
+
+Some example output is:
+
+.. code::
+
+	"proxy.process.ssl.cipher.user_agent.DES-CBC3-SHA": 0,
+	"proxy.process.ssl.cipher.user_agent.PSK-3DES-EDE-CBC-SHA": 0,
+	"plugin.system_stats.loadavg.one": 136128,
+	"plugin.system_stats.loadavg.five": 132032,
+	"plugin.system_stats.loadavg.ten": 88864,
+	"plugin.system_stats.current_processes": 503,
+	"plugin.system_stats.net.enp0s3.speed": 1000,
+	"plugin.system_stats.net.enp0s3.collisions": 0,
+	"plugin.system_stats.net.enp0s3.multicast": 0,
+	"plugin.system_stats.net.enp0s3.rx_bytes": 6783959,
+	"plugin.system_stats.net.enp0s3.rx_compressed": 0,
+	"plugin.system_stats.net.enp0s3.rx_crc_errors": 0,
+	"plugin.system_stats.net.enp0s3.rx_dropped": 0,
+	"plugin.system_stats.net.enp0s3.rx_errors": 0,
+	"plugin.system_stats.net.enp0s3.rx_fifo_errors": 0,
+	"plugin.system_stats.net.enp0s3.rx_frame_errors": 0,
+	"plugin.system_stats.net.enp0s3.rx_length_errors": 0,
+	"plugin.system_stats.net.enp0s3.rx_missed_errors": 0,
+	"plugin.system_stats.net.enp0s3.rx_nohandler": 0,
+	"plugin.system_stats.net.enp0s3.rx_over_errors": 0,
+	"plugin.system_stats.net.enp0s3.rx_packets": 9119,
+	"plugin.system_stats.net.enp0s3.tx_aborted_errors": 0,
+	"plugin.system_stats.net.enp0s3.tx_bytes": 922054,
+	"plugin.system_stats.net.enp0s3.tx_carrier_errors": 0,
+	"plugin.system_stats.net.enp0s3.tx_compressed": 0,
+	"plugin.system_stats.net.enp0s3.tx_dropped": 0,
+	"plugin.system_stats.net.enp0s3.tx_errors": 0,
+	"plugin.system_stats.net.enp0s3.tx_fifo_errors": 0,
+	"plugin.system_stats.net.enp0s3.tx_heartbeat_errors": 0,
+	"plugin.system_stats.net.enp0s3.tx_packets": 6013,
+	"plugin.system_stats.net.enp0s3.tx_window_errors": 0,
+	"proxy.process.cache.volume_0.bytes_used": 0,
+	"proxy.process.cache.volume_0.bytes_total": 268066816,
+
+This shows the system statistics inserted in with other stats. The above output
+displays the current load average, number of processes, and information on any network interfaces.
+
+This data is only updated every five seconds to not create large overhead.
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 2120cc1..9b9aefc 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -73,6 +73,7 @@ include experimental/ssl_cert_loader/Makefile.inc
 include experimental/sslheaders/Makefile.inc
 include experimental/stale_while_revalidate/Makefile.inc
 include experimental/stream_editor/Makefile.inc
+include experimental/system_stats/Makefile.inc
 include experimental/ts_lua/Makefile.inc
 include experimental/url_sig/Makefile.inc
 
diff --git a/plugins/experimental/system_stats/Makefile.inc b/plugins/experimental/system_stats/Makefile.inc
new file mode 100644
index 0000000..edba35d
--- /dev/null
+++ b/plugins/experimental/system_stats/Makefile.inc
@@ -0,0 +1,20 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+pkglib_LTLIBRARIES += experimental/system_stats/system_stats.la
+
+experimental_system_stats_system_stats_la_SOURCES = \
+experimental/system_stats/system_stats.c
diff --git a/plugins/experimental/system_stats/system_stats.c b/plugins/experimental/system_stats/system_stats.c
new file mode 100644
index 0000000..3d4dd62
--- /dev/null
+++ b/plugins/experimental/system_stats/system_stats.c
@@ -0,0 +1,256 @@
+/** @file
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "ts/ink_config.h"
+#include "ts/ink_defs.h"
+#include "ts/ts.h"
+
+#include <dirent.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_SYSINFO_H
+#include <sys/sysinfo.h>
+#endif
+
+#include <limits.h>
+
+#define PLUGIN_NAME "system_stats"
+#define DEBUG_TAG PLUGIN_NAME
+
+// Time in MS to grab the system stats
+#define SYSTEM_STATS_TIMEOUT 5000
+
+// Load Average Strings
+#define LOAD_AVG_ONE_MIN "plugin." PLUGIN_NAME ".loadavg.one"
+#define LOAD_AVG_FIVE_MIN "plugin." PLUGIN_NAME ".loadavg.five"
+#define LOAD_AVG_TEN_MIN "plugin." PLUGIN_NAME ".loadavg.ten"
+
+// Process Strings
+#define CURRENT_PROCESSES "plugin." PLUGIN_NAME ".current_processes"
+
+// Base net stats name, full name needs to populated
+// with NET_STATS.infname.RX/TX.standard_net_stats field
+#define NET_STATS "plugin." PLUGIN_NAME ".net."
+
+#define NET_STATS_DIR "/sys/class/net"
+#define STATISTICS_DIR "statistics"
+
+static int
+statAdd(const char *name, TSRecordDataType record_type, TSMutex create_mutex)
+{
+  int stat_id = -1;
+
+  TSMutexLock(create_mutex);
+
+  if (TS_ERROR == TSStatFindName((const char *)name, &stat_id)) {
+    stat_id = TSStatCreate((const char *)name, record_type, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
+    if (stat_id == TS_ERROR) {
+      TSDebug(DEBUG_TAG, "Error creating stat_name: %s", name);
+    } else {
+      TSDebug(DEBUG_TAG, "Created stat_name: %s stat_id: %d", name, stat_id);
+    }
+  }
+
+  TSMutexUnlock(create_mutex);
+
+  return stat_id;
+}
+
+static int
+getFile(const char *filename, char *buffer, int bufferSize)
+{
+  TSFile f = 0;
+  size_t s = 0;
+
+  f = TSfopen(filename, "r");
+  if (!f) {
+    buffer[0] = 0;
+    // Return -1 to indicate read err
+    return -1;
+  }
+
+  s = TSfread(f, buffer, bufferSize);
+  if (s > 0) {
+    buffer[s] = 0;
+  } else {
+    buffer[0] = 0;
+  }
+
+  TSfclose(f);
+
+  return s;
+}
+
+static void
+statSet(const char *name, int value, TSMutex stat_creation_mutex)
+{
+  int stat_id = statAdd(name, TS_RECORDDATATYPE_INT, stat_creation_mutex);
+  if (stat_id != TS_ERROR) {
+    TSStatIntSet(stat_id, value);
+  }
+}
+
+static void
+setNetStat(TSMutex stat_creation_mutex, const char *interface, const char *entry, const char *subdir)
+{
+  char sysfs_name[PATH_MAX];
+  char stat_name[255];
+  char data[255];
+
+  memset(&stat_name[0], 0, sizeof(stat_name));
+  memset(&sysfs_name[0], 0, sizeof(sysfs_name));
+  memset(&data[0], 0, sizeof(data));
+
+  if ((interface == NULL) || (entry == NULL)) {
+    TSError("%s: NULL subdir or entry", DEBUG_TAG);
+    return;
+  }
+
+  // Generate the ATS stats name
+  snprintf(&stat_name[0], sizeof(stat_name), "%s%s.%s", NET_STATS, interface, entry);
+
+  // Determine if this is a toplevel netdev stat, or one from stastistics.
+  if (subdir == NULL) {
+    snprintf(&sysfs_name[0], sizeof(sysfs_name), "%s/%s/%s", NET_STATS_DIR, interface, entry);
+  } else {
+    snprintf(&sysfs_name[0], sizeof(sysfs_name), "%s/%s/%s/%s", NET_STATS_DIR, interface, subdir, entry);
+  }
+
+  if (getFile(&sysfs_name[0], &data[0], sizeof(data)) < 0) {
+    TSDebug(DEBUG_TAG, "Error reading file %s", sysfs_name);
+  } else {
+    statSet(stat_name, atoi(data), stat_creation_mutex);
+  }
+}
+
+static int
+netStatsInfo(TSMutex stat_creation_mutex)
+{
+  struct dirent *dent;
+  DIR *srcdir = opendir(NET_STATS_DIR);
+
+  if (srcdir == NULL) {
+    return 0;
+  }
+
+  while ((dent = readdir(srcdir)) != NULL) {
+    if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0 || strcmp(dent->d_name, "lo") == 0) {
+      continue;
+    }
+
+    setNetStat(stat_creation_mutex, dent->d_name, "speed", NULL);
+    setNetStat(stat_creation_mutex, dent->d_name, "collisions", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "multicast", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_bytes", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_compressed", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_crc_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_dropped", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_fifo_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_frame_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_length_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_missed_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_nohandler", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_over_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "rx_packets", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "tx_aborted_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "tx_bytes", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "tx_carrier_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "tx_compressed", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "tx_dropped", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "tx_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "tx_fifo_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "tx_heartbeat_errors", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "tx_packets", STATISTICS_DIR);
+    setNetStat(stat_creation_mutex, dent->d_name, "tx_window_errors", STATISTICS_DIR);
+  }
+  return 0;
+}
+
+static void
+getStats(TSMutex stat_creation_mutex)
+{
+#ifdef HAVE_SYS_SYSINFO_H
+  struct sysinfo info;
+
+  sysinfo(&info);
+
+  statSet(LOAD_AVG_ONE_MIN, info.loads[0], stat_creation_mutex);
+  statSet(LOAD_AVG_FIVE_MIN, info.loads[1], stat_creation_mutex);
+  statSet(LOAD_AVG_TEN_MIN, info.loads[2], stat_creation_mutex);
+  statSet(CURRENT_PROCESSES, info.procs, stat_creation_mutex);
+#endif // #ifdef HAVE_SYS_SYSINFO_H
+  netStatsInfo(stat_creation_mutex);
+
+  return;
+}
+
+static int
+systemStatsContCB(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
+{
+  TSMutex stat_creation_mutex;
+
+  TSDebug(DEBUG_TAG, "entered %s", __FUNCTION__);
+
+  stat_creation_mutex = TSContMutexGet(cont);
+  getStats(stat_creation_mutex);
+
+  TSContSchedule(cont, SYSTEM_STATS_TIMEOUT, TS_THREAD_POOL_TASK);
+  TSDebug(DEBUG_TAG, "finished %s", __FUNCTION__);
+
+  return 0;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+  TSCont stats_cont;
+
+  info.plugin_name   = PLUGIN_NAME;
+  info.vendor_name   = "Apache Software Foundation";
+  info.support_email = "dev@trafficserver.apache.org";
+
+  if (TSPluginRegister(&info) != TS_SUCCESS) {
+    TSError("[%s] Plugin registration failed", DEBUG_TAG);
+    return;
+  } else {
+    TSDebug(DEBUG_TAG, "Plugin registration succeeded");
+  }
+
+  stats_cont = TSContCreate(systemStatsContCB, TSMutexCreate());
+  TSContDataSet(stats_cont, NULL);
+
+  // We want our first hit immediate to populate the stats,
+  // Subsequent schedules done within the function will be for
+  // 5 seconds.
+  TSContSchedule(stats_cont, 0, TS_THREAD_POOL_TASK);
+
+  TSDebug(DEBUG_TAG, "Init complete");
+}

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].