Add a new DynamicMeter class for runtime Meter extension

This commit is based on exploratory work by Sohaib Mohamed.
The end goal is two-fold - to support addition of Meters we
build via configuration files for both the PCP platform and
for scripts ( https://github.com/htop-dev/htop/issues/526 )

Here, we focus on generic code and the PCP support.  A new
class DynamicMeter is introduced - it uses the special case
'param' field handling that previously was used only by the
CPUMeter, such that every runtime-configured Meter is given
a unique identifier.  Unlike with the CPUMeter this is used
internally only.  When reading/writing to htoprc instead of
CPU(N) - where N is an integer param (CPU number) - we use
the string name for each meter.  For example, if we have a
configuration for a DynamicMeter for some Redis metrics, we
might read and write "Dynamic(redis)".  This identifier is
subsequently matched (back) up to the configuration file so
we're able to re-create arbitrary user configurations.

The PCP platform configuration file format is fairly simple.
We expand configs from several directories, including the
users homedir alongside htoprc (below htop/meters/) and also
/etc/pcp/htop/meters.  The format will be described via a
new pcp-htop(5) man page, but its basically ini-style and
each Meter has one or more metric expressions associated, as
well as specifications for labels, color and so on via a dot
separated notation for individual metrics within the Meter.

A few initial sample configuration files are provided below
./pcp/meters that give the general idea.  The PCP "derived"
metric specification - see pmRegisterDerived(3) - is used
as the syntax for specifying metrics in PCP DynamicMeters.
This commit is contained in:
Nathan Scott
2021-06-23 17:44:56 +10:00
parent 865b85eb2d
commit f0ed0fdafb
48 changed files with 1044 additions and 68 deletions

368
pcp/PCPDynamicMeter.c Normal file
View File

@ -0,0 +1,368 @@
/*
htop - PCPDynamicMeter.c
(C) 2021 htop dev team
(C) 2021 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "pcp/PCPDynamicMeter.h"
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "Object.h"
#include "Platform.h"
#include "ProcessList.h"
#include "RichString.h"
#include "Settings.h"
#include "XUtils.h"
static PCPDynamicMetric* PCPDynamicMeter_lookupMetric(PCPDynamicMeters* meters, PCPDynamicMeter* meter, const char* name) {
size_t bytes = 8 + strlen(meter->super.name) + strlen(name);
char* metricName = xMalloc(bytes);
xSnprintf(metricName, bytes, "htop.%s.%s", meter->super.name, name);
PCPDynamicMetric* metric;
for (unsigned int i = 0; i < meter->totalMetrics; i++) {
metric = &meter->metrics[i];
if (String_eq(metric->name, metricName)) {
free(metricName);
return metric;
}
}
/* not an existing metric in this meter - add it */
unsigned int n = meter->totalMetrics + 1;
meter->metrics = xReallocArray(meter->metrics, n, sizeof(PCPDynamicMetric));
meter->totalMetrics = n;
metric = &meter->metrics[n-1];
memset(metric, 0, sizeof(PCPDynamicMetric));
metric->name = metricName;
metric->id = meters->offset + meters->cursor;
meters->cursor++;
Platform_addMetric(metric->id, metricName);
return metric;
}
static void PCPDynamicMeter_parseMetric(PCPDynamicMeters* meters, PCPDynamicMeter* meter, const char *path, unsigned int line, char* key, char* value) {
PCPDynamicMetric *metric;
char* p;
if ((p = strchr(key, '.')) == NULL)
return;
*p++ = '\0'; /* end the name, p is now the attribute, e.g. 'label' */
if (String_eq(p, "metric")) {
/* lookup a dynamic metric with this name, else create */
metric = PCPDynamicMeter_lookupMetric(meters, meter, key);
/* use derived metrics in dynamic meters for simplicity */
char* error;
if (pmRegisterDerivedMetric(metric->name, value, &error) < 0) {
char note[1024];
xSnprintf(note, sizeof(note),
"failed to parse expression in %s at line %u\n%s\n%s",
path, line, error, pmGetProgname());
free(error);
errno = EINVAL;
CRT_fatalError(note);
}
} else {
/* this is a property of a dynamic metric - the metric expression */
/* may not have been observed yet - i.e. we allow for any ordering */
metric = PCPDynamicMeter_lookupMetric(meters, meter, key);
if (String_eq(p, "color")) {
if (String_eq(value, "gray"))
metric->color = DYNAMIC_GRAY;
else if (String_eq(value, "darkgray"))
metric->color = DYNAMIC_DARKGRAY;
else if (String_eq(value, "red"))
metric->color = DYNAMIC_RED;
else if (String_eq(value, "green"))
metric->color = DYNAMIC_GREEN;
else if (String_eq(value, "blue"))
metric->color = DYNAMIC_BLUE;
else if (String_eq(value, "cyan"))
metric->color = DYNAMIC_CYAN;
else if (String_eq(value, "magenta"))
metric->color = DYNAMIC_MAGENTA;
else if (String_eq(value, "yellow"))
metric->color = DYNAMIC_YELLOW;
else if (String_eq(value, "white"))
metric->color = DYNAMIC_WHITE;
} else if (String_eq(p, "label")) {
free_and_xStrdup(&metric->label, value);
} else if (String_eq(p, "suffix")) {
free_and_xStrdup(&metric->suffix, value);
}
}
}
// Ensure a valid name for use in a PCP metric name and in htoprc
static void PCPDynamicMeter_validateMeterName(char* key, const char *path, unsigned int line) {
char* p = key;
char* end = strrchr(key, ']');
if (end) {
*end = '\0';
} else {
char note[1024];
xSnprintf(note, sizeof(note),
"No closing brace on meter name at %s line %u\n\"%s\"",
path, line, key);
errno = EINVAL;
CRT_fatalError(note);
}
while (*p) {
if (p == key) {
if (!isalpha(*p) && *p != '_')
break;
} else {
if (!isalnum(*p) && *p != '_')
break;
}
p++;
}
if (*p != '\0') { /* badness */
char note[1024];
xSnprintf(note, sizeof(note),
"Invalid meter name at %s line %u\n\"%s\"",
path, line, key);
errno = EINVAL;
CRT_fatalError(note);
} else { /* overwrite closing brace */
*p = '\0';
}
}
static PCPDynamicMeter* PCPDynamicMeter_new(PCPDynamicMeters* meters, const char* name) {
PCPDynamicMeter* meter = xCalloc(1, sizeof(*meter));
String_safeStrncpy(meter->super.name, name, sizeof(meter->super.name));
Hashtable_put(meters->table, ++meters->count, meter);
return meter;
}
static void PCPDynamicMeter_parseFile(PCPDynamicMeters* meters, const char* path) {
FILE* file = fopen(path, "r");
if (!file)
return;
PCPDynamicMeter* meter = NULL;
unsigned int lineno = 0;
for (;;) {
char* line = String_readLine(file);
if (!line)
break;
lineno++;
/* cleanup whitespace, skip comment lines */
char* trimmed = String_trim(line);
free(line);
if (trimmed[0] == '#' || trimmed[0] == '\0') {
free(trimmed);
continue;
}
size_t n;
char** config = String_split(trimmed, '=', &n);
free(trimmed);
if (config == NULL)
continue;
char* key = String_trim(config[0]);
char* value = n > 1 ? String_trim(config[1]) : NULL;
if (key[0] == '[') { /* new section heading - i.e. new meter */
PCPDynamicMeter_validateMeterName(key+1, path, lineno);
meter = PCPDynamicMeter_new(meters, key+1);
} else if (value && String_eq(key, "caption")) {
free_and_xStrdup(&meter->super.caption, value);
} else if (value && String_eq(key, "description")) {
free_and_xStrdup(&meter->super.description, value);
} else if (value && String_eq(key, "type")) {
if (String_eq(config[1], "bar"))
meter->super.type = BAR_METERMODE;
else if (String_eq(config[1], "text"))
meter->super.type = TEXT_METERMODE;
else if (String_eq(config[1], "graph"))
meter->super.type = GRAPH_METERMODE;
else if (String_eq(config[1], "led"))
meter->super.type = LED_METERMODE;
} else if (value && String_eq(key, "maximum")) {
meter->super.maximum = strtod(value, NULL);
} else if (value) {
PCPDynamicMeter_parseMetric(meters, meter, path, lineno, key, value);
}
String_freeArray(config);
free(value);
free(key);
}
fclose(file);
}
static void PCPDynamicMeter_scanDir(PCPDynamicMeters* meters, char* path) {
DIR* dir = opendir(path);
if (!dir)
return;
struct dirent *dirent;
while ((dirent = readdir(dir)) != NULL) {
if (dirent->d_name[0] == '.')
continue;
char *file = String_cat(path, dirent->d_name);
PCPDynamicMeter_parseFile(meters, file);
free(file);
}
closedir(dir);
}
void PCPDynamicMeters_init(PCPDynamicMeters* meters) {
const char* sysconf = pmGetConfig("PCP_SYSCONF_DIR");
const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
const char* home = getenv("HOME");
char* path;
meters->table = Hashtable_new(0, true);
/* search in the users home directory first of all */
if (xdgConfigHome) {
path = String_cat(xdgConfigHome, "/htop/meters/");
} else {
if (!home)
home = "";
path = String_cat(home, "/.config/htop/meters/");
}
PCPDynamicMeter_scanDir(meters, path);
free(path);
/* secondly search in the system meters directory */
path = String_cat(sysconf, "/htop/meters/");
PCPDynamicMeter_scanDir(meters, path);
free(path);
/* check the working directory, as a final option */
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
path = String_cat(cwd, "/pcp/meters/");
PCPDynamicMeter_scanDir(meters, path);
free(path);
}
}
void PCPDynamicMeter_enable(PCPDynamicMeter* this) {
for (unsigned int i = 0; i < this->totalMetrics; i++)
Metric_enable(this->metrics[i].id, true);
}
void PCPDynamicMeter_updateValues(PCPDynamicMeter* this, Meter* meter) {
char* buffer = meter->txtBuffer;
size_t size = sizeof(meter->txtBuffer);
size_t bytes = 0;
for (unsigned int i = 0; i < this->totalMetrics; i++) {
if (i > 0 && bytes < size - 1)
buffer[bytes++] = '/'; /* separator */
PCPDynamicMetric* metric = &this->metrics[i];
const pmDesc* desc = Metric_desc(metric->id);
pmAtomValue atom;
if (!Metric_values(metric->id, &atom, 1, desc->type)) {
bytes--; /* clear the separator */
continue;
}
/* TODO: pretty-print the values - pmConvScale, etc */
switch (desc->type) {
case PM_TYPE_STRING:
bytes += xSnprintf(buffer + bytes, size - bytes, "%s", atom.cp);
free(atom.cp);
break;
case PM_TYPE_32:
bytes += xSnprintf(buffer + bytes, size - bytes, "%d", atom.l);
break;
case PM_TYPE_U32:
bytes += xSnprintf(buffer + bytes, size - bytes, "%u", atom.ul);
break;
case PM_TYPE_64:
bytes += xSnprintf(buffer + bytes, size - bytes, "%lld", (long long) atom.ll);
break;
case PM_TYPE_U64:
bytes += xSnprintf(buffer + bytes, size - bytes, "%llu", (unsigned long long) atom.ull);
break;
case PM_TYPE_FLOAT:
bytes += xSnprintf(buffer + bytes, size - bytes, "%f", (double) atom.f);
break;
case PM_TYPE_DOUBLE:
bytes += xSnprintf(buffer + bytes, size - bytes, "%f", atom.d);
break;
default:
break;
}
}
if (!bytes)
xSnprintf(buffer, size, "no data");
}
void PCPDynamicMeter_display(PCPDynamicMeter* this, ATTR_UNUSED const Meter* meter, RichString* out) {
int nodata = 1;
for (unsigned int i = 0; i < this->totalMetrics; i++) {
PCPDynamicMetric* metric = &this->metrics[i];
const pmDesc* desc = Metric_desc(metric->id);
pmAtomValue atom;
char buffer[64];
int len;
if (!Metric_values(metric->id, &atom, 1, desc->type))
continue;
nodata = 0;
if (i > 0)
RichString_appendnAscii(out, CRT_colors[metric->color], " ", 1);
if (metric->label) {
len = xSnprintf(buffer, sizeof(buffer), "%s ", metric->label);
RichString_appendnAscii(out, CRT_colors[metric->color], buffer, len);
}
/* TODO: pretty-print the values - pmConvScale, etc */
len = 0;
switch (desc->type) {
case PM_TYPE_STRING:
len = xSnprintf(buffer, sizeof(buffer), "%s", atom.cp);
free(atom.cp);
break;
case PM_TYPE_32:
len = xSnprintf(buffer, sizeof(buffer), "%d", atom.l);
break;
case PM_TYPE_U32:
len = xSnprintf(buffer, sizeof(buffer), "%u", atom.ul);
break;
case PM_TYPE_64:
len = xSnprintf(buffer, sizeof(buffer), "%lld", (long long) atom.ll);
break;
case PM_TYPE_U64:
len = xSnprintf(buffer, sizeof(buffer), "%llu", (unsigned long long) atom.ull);
break;
case PM_TYPE_FLOAT:
len = xSnprintf(buffer, sizeof(buffer), "%f", (double)atom.f);
break;
case PM_TYPE_DOUBLE:
len = xSnprintf(buffer, sizeof(buffer), "%f", atom.d);
break;
default:
break;
}
if (len)
RichString_appendnAscii(out, CRT_colors[metric->color], buffer, len);
}
if (nodata)
RichString_writeAscii(out, CRT_colors[METER_VALUE_ERROR], "no data");
}

36
pcp/PCPDynamicMeter.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef HEADER_PCPDynamicMeter
#define HEADER_PCPDynamicMeter
#include "CRT.h"
#include "DynamicMeter.h"
typedef struct {
unsigned int id; /* index into metric array */
ColorElements color;
char* name; /* derived metric name */
char* label;
char* suffix;
} PCPDynamicMetric;
typedef struct {
DynamicMeter super;
PCPDynamicMetric *metrics;
unsigned int totalMetrics;
} PCPDynamicMeter;
typedef struct {
Hashtable* table;
unsigned int count; /* count of dynamic meters discovered by scan */
unsigned int offset; /* start offset into the Platform metric array */
unsigned int cursor; /* identifier allocator for each new metric used */
} PCPDynamicMeters;
void PCPDynamicMeters_init(PCPDynamicMeters* meters);
void PCPDynamicMeter_enable(PCPDynamicMeter* this);
void PCPDynamicMeter_updateValues(PCPDynamicMeter* this, Meter* meter);
void PCPDynamicMeter_display(PCPDynamicMeter* this, const Meter* meter, RichString* out);
#endif

View File

@ -59,11 +59,11 @@ static char* setUser(UsersTable* this, unsigned int uid, int pid, int offset) {
return name;
}
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
PCPProcessList* this = xCalloc(1, sizeof(PCPProcessList));
ProcessList* super = &(this->super);
ProcessList_init(super, Class(PCPProcess), usersTable, pidMatchList, userId);
ProcessList_init(super, Class(PCPProcess), usersTable, dynamicMeters, pidMatchList, userId);
struct timeval timestamp;
gettimeofday(&timestamp, NULL);

View File

@ -63,7 +63,7 @@ typedef struct PCPProcessList_ {
ZfsArcStats zfs;
} PCPProcessList;
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId);
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId);
void ProcessList_delete(ProcessList* pl);

View File

@ -20,6 +20,7 @@ in the source distribution for its full text.
#include "DateMeter.h"
#include "DateTimeMeter.h"
#include "DiskIOMeter.h"
#include "DynamicMeter.h"
#include "HostnameMeter.h"
#include "LoadAverageMeter.h"
#include "Macros.h"
@ -41,6 +42,7 @@ in the source distribution for its full text.
#include "linux/PressureStallMeter.h"
#include "linux/ZramMeter.h"
#include "linux/ZramStats.h"
#include "pcp/PCPDynamicMeter.h"
#include "pcp/PCPProcess.h"
#include "pcp/PCPProcessList.h"
#include "zfs/ZfsArcMeter.h"
@ -50,14 +52,14 @@ in the source distribution for its full text.
typedef struct Platform_ {
int context; /* PMAPI(3) context identifier */
unsigned int total; /* total number of all metrics */
unsigned int totalMetrics; /* total number of all metrics */
const char** names; /* name array indexed by Metric */
pmID* pmids; /* all known metric identifiers */
pmID* fetch; /* enabled identifiers for sampling */
pmDesc* descs; /* metric desc array indexed by Metric */
pmResult* result; /* sample values result indexed by Metric */
PCPDynamicMeters meters; /* dynamic meters via configuration files */
struct timeval offset; /* time offset used in archive mode only */
long long btime; /* boottime in seconds since the epoch */
char* release; /* uname and distro from this context */
int pidmax; /* maximum platform process identifier */
@ -78,6 +80,7 @@ const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
const MeterClass* const Platform_meterTypes[] = {
&CPUMeter_class,
&DynamicMeter_class,
&ClockMeter_class,
&DateMeter_class,
&DateTimeMeter_class,
@ -244,7 +247,13 @@ static const char *Platform_metricNames[] = {
[PCP_METRIC_COUNT] = NULL
};
const pmDesc* Metric_desc(Metric metric) {
return &pcp->descs[metric];
}
pmAtomValue* Metric_values(Metric metric, pmAtomValue *atom, int count, int type) {
if (pcp->result == NULL)
return NULL;
pmValueSet* vset = pcp->result->vset[metric];
if (!vset || vset->numval <= 0)
@ -374,7 +383,7 @@ bool Metric_fetch(struct timeval *timestamp) {
pmFreeResult(pcp->result);
pcp->result = NULL;
}
int sts = pmFetch(pcp->total, pcp->fetch, &pcp->result);
int sts = pmFetch(pcp->totalMetrics, pcp->fetch, &pcp->result);
if (sts < 0) {
if (pmDebugOptions.appl0)
fprintf(stderr, "Error: cannot fetch metric values: %s\n",
@ -386,12 +395,12 @@ bool Metric_fetch(struct timeval *timestamp) {
return true;
}
static int Platform_addMetric(Metric id, const char *name) {
int Platform_addMetric(Metric id, const char *name) {
unsigned int i = (unsigned int)id;
if (i >= PCP_METRIC_COUNT && i >= pcp->total) {
if (i >= PCP_METRIC_COUNT && i >= pcp->totalMetrics) {
/* added via configuration files */
unsigned int j = pcp->total + 1;
unsigned int j = pcp->totalMetrics + 1;
pcp->fetch = xRealloc(pcp->fetch, j * sizeof(pmID));
pcp->pmids = xRealloc(pcp->pmids, j * sizeof(pmID));
pcp->names = xRealloc(pcp->names, j * sizeof(char*));
@ -401,7 +410,7 @@ static int Platform_addMetric(Metric id, const char *name) {
pcp->pmids[i] = pcp->fetch[i] = PM_ID_NULL;
pcp->names[i] = name;
return ++pcp->total;
return ++pcp->totalMetrics;
}
/* global state from the environment and command line arguments */
@ -449,14 +458,17 @@ void Platform_init(void) {
for (unsigned int i = 0; i < PCP_METRIC_COUNT; i++)
Platform_addMetric(i, Platform_metricNames[i]);
pcp->meters.offset = PCP_METRIC_COUNT;
sts = pmLookupName(pcp->total, pcp->names, pcp->pmids);
PCPDynamicMeters_init(&pcp->meters);
sts = pmLookupName(pcp->totalMetrics, pcp->names, pcp->pmids);
if (sts < 0) {
fprintf(stderr, "Error: cannot lookup metric names: %s\n", pmErrStr(sts));
exit(1);
}
for (unsigned int i = 0; i < pcp->total; i++) {
for (unsigned int i = 0; i < pcp->totalMetrics; i++) {
pcp->fetch[i] = PM_ID_NULL; /* default is to not sample */
/* expect some metrics to be missing - e.g. PMDA not available */
@ -883,3 +895,25 @@ void Platform_gettime_monotonic(uint64_t* msec) {
struct timeval* tv = &pcp->result->timestamp;
*msec = ((uint64_t)tv->tv_sec * 1000) + ((uint64_t)tv->tv_usec / 1000);
}
Hashtable* Platform_dynamicMeters(void) {
return pcp->meters.table;
}
void Platform_dynamicMeterInit(Meter* meter) {
PCPDynamicMeter* this = Hashtable_get(pcp->meters.table, meter->param);
if (this)
PCPDynamicMeter_enable(this);
}
void Platform_dynamicMeterUpdateValues(Meter* meter) {
PCPDynamicMeter* this = Hashtable_get(pcp->meters.table, meter->param);
if (this)
PCPDynamicMeter_updateValues(this, meter);
}
void Platform_dynamicMeterDisplay(const Meter* meter, RichString* out) {
PCPDynamicMeter* this = Hashtable_get(pcp->meters.table, meter->param);
if (this)
PCPDynamicMeter_display(this, meter, out);
}

View File

@ -24,6 +24,7 @@ in the source distribution for its full text.
#include "Action.h"
#include "BatteryMeter.h"
#include "DiskIOMeter.h"
#include "Hashtable.h"
#include "Meter.h"
#include "NetworkIOMeter.h"
#include "Process.h"
@ -247,14 +248,26 @@ bool Metric_iterate(Metric metric, int* instp, int* offsetp);
pmAtomValue* Metric_values(Metric metric, pmAtomValue *atom, int count, int type);
const pmDesc* Metric_desc(Metric metric);
int Metric_instanceCount(Metric metric);
int Metric_instanceOffset(Metric metric, int inst);
pmAtomValue *Metric_instance(Metric metric, int inst, int offset, pmAtomValue *atom, int type);
pmAtomValue* Metric_instance(Metric metric, int inst, int offset, pmAtomValue *atom, int type);
int Platform_addMetric(Metric id, const char *name);
void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec);
void Platform_gettime_monotonic(uint64_t* msec);
Hashtable* Platform_dynamicMeters(void);
void Platform_dynamicMeterInit(Meter* meter);
void Platform_dynamicMeterUpdateValues(Meter* meter);
void Platform_dynamicMeterDisplay(const Meter* meter, RichString* out);
#endif

9
pcp/meters/entropy Normal file
View File

@ -0,0 +1,9 @@
#
# pcp-htop(1) configuration file - see pcp-htop(5)
#
[entropy]
caption = Entropy
avail.metric = kernel.all.entropy.avail / kernel.all.entropy.poolsize * 100
avail.label = avail
avail.suffix = %

11
pcp/meters/freespace Normal file
View File

@ -0,0 +1,11 @@
#
# pcp-htop(1) configuration file - see pcp-htop(5)
#
[freespace]
caption = Freespace
description = Filesystem space
used.metric = sum(filesys.used)
used.color = blue
free.metric = sum(filesys.free)
free.color = green

13
pcp/meters/ipc Normal file
View File

@ -0,0 +1,13 @@
#
# pcp-htop(1) configuration file - see pcp-htop(5)
#
[ipc]
caption = SysV IPC
description = SysV IPC counts
msg.metric = ipc.msg.used_queues
msg.color = blue
sem.metric = ipc.sem.used_sem
sem.color = green
shm.metric = ipc.shm.used_ids
shm.color = cyan

15
pcp/meters/locks Normal file
View File

@ -0,0 +1,15 @@
#
# pcp-htop(1) configuration file - see pcp-htop(5)
#
[locks]
caption = File locks
description = VFS file locks
posix.metric = vfs.locks.posix.count
posix.color = blue
flock.metric = vfs.locks.flock.count
flock.color = green
readlock.metric = vfs.locks.posix.read + vfs.locks.flock.read
readlock.color = red
writelock.metric = vfs.locks.posix.write + vfs.locks.flock.write
writelock.color = yellow

11
pcp/meters/memcache Normal file
View File

@ -0,0 +1,11 @@
#
# pcp-htop(1) configuration file - see pcp-htop(5)
#
[memcache]
caption = Memcache
description = Memcache Hits
hit.metric = sum(memcache.hits)
hit.color = green
miss.metric = sum(memcache.misses)
miss.color = blue

73
pcp/meters/mysql Normal file
View File

@ -0,0 +1,73 @@
#
# pcp-htop(1) configuration file - see pcp-htop(5)
#
[mysql_io]
caption = MySQL I/O
recv.metric = mysql.status.bytes_received
recv.color = green
recv.label = recv
sent.metric = mysql.status.bytes_sent
sent.color = blue
sent.label = sent
[mysql_keys]
caption = MySQL keys
description = MySQL key status
key_blocks_used.metric = mysql.status.key_blocks_used
key_blocks_used.label = color
key_blocks_used.label = used
key_reads.metric = mysql.status.key_reads
key_reads.label = read
key_reads.color = green
key_writes.metric = mysql.status.key_writes
key_writes.label = writ
key_writes.color = blue
key_read_requests.metric = mysql.status.key_read_requests
key_read_requests.label = rreq
key_read_requests.color = green
key_write_requests.metric = mysql.status.key_write_requests
key_write_requests.label = wreq
key_write_requests.color = blue
[innodb_buffer]
caption = InnoDB pool
description = InnoDB buffer pool
created.metric = mysql.status.innodb_pages_created
created.label = cr
created.color = yellow
read.metric = mysql.status.innodb_pages_read
read.label = rd
read.color = greed
written.metric = mysql.status.innodb_pages_written
written.label = wr
written.color = red
[innodb_io]
caption = InnoDB I/O
description = InnoDB I/O operations
read.metric = mysql.status.innodb_data_read
read.label = rd
read.color = green
written.metric = mysql.status.innodb_data.writes
written.label = wr
written.color = blue
sync.metric = mysql.status.innodb_data_fsyncs
sync.label = sync
sync.color = cyan
[innodb_ops]
caption = InnoDB ops
description = InnoDB operations
inserted.metric = mysql.status.innodb_rows_inserted
inserted.label = ins
inserted.color = blue
updated.metric = mysql.status.innodb_rows_updated
updated.label = upd
updated.color = cyan
deleted.metric = mysql.status.innodb_rows_deleted
deleted.label = del
deleted.color = red
read.metric = mysql.status.innodb_rows_read
read.label = rd
read.color = green

21
pcp/meters/postfix Normal file
View File

@ -0,0 +1,21 @@
#
# pcp-htop(1) configuration file - see pcp-htop(5)
#
[postfix]
caption = Postfix
incoming.metric = sum(postfix.queues.incoming)
incoming.color = green
incoming.label = in
active.metric = sum(postfix.queues.active)
active.color = blue
active.label = act
deferred.metric = sum(postfix.queues.deferred)
deferred.color = cyan
deferred.label = dfr
bounce.metric = sum(postfix.queues.maildrop)
bounce.color = red
bounce.label = bnc
hold.metric = sum(postfix.queues.hold)
hold.color = yellow
hold.label = hold

41
pcp/meters/redis Normal file
View File

@ -0,0 +1,41 @@
#
# pcp-htop(1) configuration file - see pcp-htop(5)
#
[redisxact]
caption = Redis xact
description = Redis transactions
tps.metric = redis.instantaneous_ops_per_sec
tps.color = green
[redismem]
caption = Redis mem
description = Redis memory
lua.metric = redis.used_memory_lua
lua.color = magenta
lua.label = lua:
used.metric = redis.used_memory
used.color = blue
used.label = used:
[redisclient]
caption = Redis clients
description = Redis clients
type = bar
blocked.metric = redis.blocked_clients
blocked.color = blue
blocked.label = blk
clients.metric = redis.connected_clients
clients.color = green
clients.label = conn
[redisconn]
caption = Redis conn
description = Redis connections
type = bar
reject.metric = redis.rejected_connections
reject.color = magenta
reject.label = fail/s
total.metric = redis.total_connections_received
total.color = blue
total.label = conn/s

22
pcp/meters/tcp Normal file
View File

@ -0,0 +1,22 @@
#
# pcp-htop(1) configuration file - see pcp-htop(5)
#
[tcp]
caption = TCP
description = TCP sockets
listen.metric = network.tcpconn.listen
listen.color = green
listen.label = lis
active.metric = network.tcpconn.established
active.color = blue
active.label = act
syn.metric = network.tcpconn.syn_sent + network.tcpconn.syn_recv + network.tcpconn.last_ack
syn.color = cyan
syn.label = syn
wait.metric = network.tcpconn.time_wait
wait.color = red
wait.label = tim
close.metric = network.tcpconn.fin_wait1 + network.tcpconn.fin_wait2 + network.tcpconn.close + network.tcpconn.close_wait + network.tcpconn.closing
close.color = yellow
close.label = clo