[collectd] nfs client stats

Jason Pepas cell at ices.utexas.edu
Wed Nov 2 00:38:21 CET 2005


Hello,

Here is what I have come up with for collecting nfs client statistics
after an afternoon of hacking.

some caveats:
* I am not familiar with automake/autoconf, so I don't know how to
  integrate this into the rest of collectd.
* I haven't spent enough time going over the collectd code to really
  understand what is going on, so all of the *_write() functions are
  probably broken, etc.

I hope someone else can take up the rest of the slack where I left off
:)

-jason pepas
-------------- next part --------------
#include "nfs.h"

#if COLLECT_NFS
#define MODULE_NAME "nfs"

#include "plugin.h"
#include "common.h"

static char *nfs_net_file = "nfs_net.rrd";
static char *nfs_rpc_file = "nfs_rpc.rrd";
static char *nfs_v2_file = "nfs_v2.rrd";
static char *nfs_v3_file = "nfs_v2.rrd";

/*
see /proc/net/rpc/nfs
see http://www.missioncriticallinux.com/orph/NFS-Statistics

net x x x x
rpc_stat.netcnt         Not used; always zero.
rpc_stat.netudpcnt      Not used; always zero.
rpc_stat.nettcpcnt      Not used; always zero.
rpc_stat.nettcpconn     Not used; always zero.

rpc x x x
rpc_stat.rpccnt             The number of RPC calls.
rpc_stat.rpcretrans         The number of retransmitted RPC calls.
rpc_stat.rpcauthrefresh     The number of credential refreshes.

proc2 x x x...
proc3 x x x...

Procedure   NFS Version NFS Version 3
Number      Procedures  Procedures

0           null        null
1           getattr     getattr
2           setattr     setattr
3           root        lookup
4           lookup      access
5           readlink    readlink
6           read        read
7           wrcache     write
8           write       create
9           create      mkdir
10          remove      symlink
11          rename      mknod
12          link        remove
13          symlink     rmdir
14          mkdir       rename
15          rmdir       link
16          readdir     readdir
17          fsstat      readdirplus
18                      fsstat
19                      fsinfo
20                      pathconf
21                      commit
*/

typedef struct nfs_net_stats
{
    unsigned long long netcnt;
    unsigned long long netudpcnt;
    unsigned long long nettcpcnt;
    unsigned long long nettcpcon;
} nfs_net_stats_t;

typedef struct nfs_rpc_stats
{
    unsigned long long rpccnt;
    unsigned long long rpcretrans;
    unsigned long long rpcauthrefresh;
} nfs_rpc_stats_t;

typedef struct nfs_v2_stats
{
    unsigned long long v2null;
    unsigned long long v2getattr;
    unsigned long long v2setattr;
    unsigned long long v2root;
    unsigned long long v2lookup;
    unsigned long long v2readlink;
    unsigned long long v2read;
    unsigned long long v2wrcache;
    unsigned long long v2write;
    unsigned long long v2create;
    unsigned long long v2remove;
    unsigned long long v2rename;
    unsigned long long v2link;
    unsigned long long v2symlink;
    unsigned long long v2mkdir;
    unsigned long long v2rmdir;
    unsigned long long v2readdir;
    unsigned long long v2fsstat;
} nfs_v2_stats_t;

typedef struct nfs_v3_stats
{
    unsigned long long v3null;
    unsigned long long v3getattr;
    unsigned long long v3setattr;
    unsigned long long v3lookup;
    unsigned long long v3access;
    unsigned long long v3readlink;
    unsigned long long v3read;
    unsigned long long v3write;
    unsigned long long v3create;
    unsigned long long v3mkdir;
    unsigned long long v3symlink;
    unsigned long long v3mknod;
    unsigned long long v3remove;
    unsigned long long v3rmdir;
    unsigned long long v3rename;
    unsigned long long v3link;
    unsigned long long v3readdir;
    unsigned long long v3readdirplus;
    unsigned long long v3fsstat;
    unsigned long long v3fsinfo;
    unsigned long long v3pathconf;
    unsigned long long v3commit;
} nfs_v3_stats_t;

static char *nfs_net_ds_def[] =
{
    "DS:netcnt:COUNTER:25:0:U",
    "DS:netudpcnt:COUNTER:25:0:U",
    "DS:nettcpcnt:COUNTER:25:0:U",
    "DS:nettcpcon:COUNTER:25:0:U", // should be gauge?
    NULL
};
static int nfs_net_ds_num = 4;

static char *nfs_rpc_ds_def[] =
{
    "DS:rpccnt:COUNTER:25:0:U",
    "DS:rpcretrans:COUNTER:25:0:U",
    "DS:rpcauthrefresh:COUNTER:25:0:U",
    NULL
};
static int nfs_rpc_ds_num = 3;

static char *nfs_v2_ds_def[] =
{
    "DS:v2getattr:COUNTER:25:0:U",
    "DS:v2setattr:COUNTER:25:0:U",
    "DS:v2root:COUNTER:25:0:U",
    "DS:v2lookup:COUNTER:25:0:U",
    "DS:v2readlink:COUNTER:25:0:U",
    "DS:v2read:COUNTER:25:0:U",
    "DS:v2wrcache:COUNTER:25:0:U",
    "DS:v2write:COUNTER:25:0:U",
    "DS:v2create:COUNTER:25:0:U",
    "DS:v2remove:COUNTER:25:0:U",
    "DS:v2rename:COUNTER:25:0:U",
    "DS:v2link:COUNTER:25:0:U",
    "DS:v2symlink:COUNTER:25:0:U",
    "DS:v2mkdir:COUNTER:25:0:U",
    "DS:v2rmdir:COUNTER:25:0:U",
    "DS:v2readdir:COUNTER:25:0:U",
    "DS:v2fsstat:COUNTER:25:0:U",
    NULL
};
static int nfs_v2_ds_num = 17;

static char *nfs_v3_ds_def[] =
{
    "DS:v3getattr:COUNTER:25:0:U",
    "DS:v3setattr:COUNTER:25:0:U",
    "DS:v3lookup:COUNTER:25:0:U",
    "DS:v3access:COUNTER:25:0:U",
    "DS:v3readlink:COUNTER:25:0:U",
    "DS:v3read:COUNTER:25:0:U",
    "DS:v3write:COUNTER:25:0:U",
    "DS:v3create:COUNTER:25:0:U",
    "DS:v3mkdir:COUNTER:25:0:U",
    "DS:v3symlink:COUNTER:25:0:U",
    "DS:v3mknod:COUNTER:25:0:U",
    "DS:v3remove:COUNTER:25:0:U",
    "DS:v3rmdir:COUNTER:25:0:U",
    "DS:v3rename:COUNTER:25:0:U",
    "DS:v3link:COUNTER:25:0:U",
    "DS:v2readdir:COUNTER:25:0:U",
    "DS:v3readdirplus:COUNTER:25:0:U",
    "DS:v3fsstat:COUNTER:25:0:U",
    "DS:v3fsinfo:COUNTER:25:0:U",
    "DS:v3pathconf:COUNTER:25:0:U",
    "DS:v3commit:COUNTER:25:0:U",
    NULL
};
static int nfs_v3_ds_num = 21;

extern time_t curtime;

void nfs_net_write (char *host, char *inst, char *val)
{
    rrd_update_file (host, nfs_net_file, val, nfs_net_ds_def, nfs_net_ds_num);
}

void nfs_rpc_write (char *host, char *inst, char *val)
{
    rrd_update_file (host, nfs_rpc_file, val, nfs_rpc_ds_def, nfs_rpc_ds_num);
}

void nfs_v2_write (char *host, char *inst, char *val)
{
    rrd_update_file (host, nfs_v2_file, val, nfs_v2_ds_def, nfs_v2_ds_num);
}

void nfs_v3_write (char *host, char *inst, char *val)
{
    rrd_update_file (host, nfs_v3_file, val, nfs_v3_ds_def, nfs_v3_ds_num);
}

#define BUFSIZE 1024
void nfs_net_submit(nfs_net_stats_t *net_stats)
{
    char buf[BUFSIZE];
    int retval = 0;

    retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu",
                      (unsigned int) curtime, net_stats->netcnt, net_stats->netudpcnt, net_stats->nettcpcnt, net_stats->nettcpcon);
    if (retval < 0 || retval >= BUFSIZE)
    {
        syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
        return;
    }

    plugin_submit ("nfs_rpc", "-", buf);
}
#undef BUFSIZE

#define BUFSIZE 1024
void nfs_rpc_submit(nfs_rpc_stats_t *rpc_stats)
{
    char buf[BUFSIZE];
    int retval = 0;

    retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu",
                      (unsigned int) curtime, rpc_stats->rpccnt, rpc_stats->rpcretrans, rpc_stats->rpcauthrefresh);
    if (retval < 0 || retval >= BUFSIZE)
    {
        syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
        return;
    }

    plugin_submit("nfs_rpc", "-", buf);
}
#undef BUFSIZE

#define BUFSIZE 1024
void nfs_v2_submit(nfs_v2_stats_t *v2_stats)
{
    char buf[BUFSIZE];
    int retval = 0;

    retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu...",
                      (unsigned int) curtime, v2_stats->v2null, v2_stats->v2getattr, v2_stats->v2setattr, v2_stats->v2root, v2_stats->v2lookup,
                      v2_stats->v2readlink, v2_stats->v2read, v2_stats->v2wrcache, v2_stats->v2write, v2_stats->v2create, v2_stats->v2remove, v2_stats->v2rename,
                      v2_stats->v2link, v2_stats->v2symlink, v2_stats->v2mkdir, v2_stats->v2rmdir, v2_stats->v2readdir, v2_stats->v2fsstat);
    if (retval < 0 || retval >= BUFSIZE)
    {
        syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
        return;
    }

    plugin_submit ("nfs_v2", "-", buf);
}
#undef BUFSIZE

#define BUFSIZE 1024
void nfs_v3_submit(nfs_v3_stats_t *v3_stats)
{
    char buf[BUFSIZE];
    int retval = 0;

    retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu...",
                      (unsigned int) curtime, v3_stats->v3null, v3_stats->v3getattr, v3_stats->v3setattr, v3_stats->v3lookup, v3_stats->v3access,
                      v3_stats->v3readlink, v3_stats->v3read, v3_stats->v3write, v3_stats->v3create, v3_stats->v3mkdir, v3_stats->v3symlink, v3_stats->v3mknod, v3_stats->v3remove,
                      v3_stats->v3rmdir, v3_stats->v3rename, v3_stats->v3link, v3_stats->v3readdir, v3_stats->v3readdirplus, v3_stats->v3fsstat, v3_stats->v3fsinfo, v3_stats->v3pathconf, v3_stats->v3commit);
    if (retval < 0 || retval >= BUFSIZE)
    {
        syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
        return;
    }

    plugin_submit("nfs_v3", "-", buf);
}
#undef BUFSIZE

#define BUFSIZE 512
void nfs_net_read (void)
{
    FILE *fp;
    char buffer[BUFSIZE];
    nfs_net_stats_t net_stats; 

    fp = fopen("/proc/net/rpc/nfs", "r");
    if (fp == NULL)
    {
        syslog (LOG_ERR, "load: fopen: %s", strerror(errno));
        return;
    }

    // line 1: "net x x x x"
    {
        char *fields[5];
        int numfields = 0;

        {
            char *retval = NULL;
            retval = fgets(buffer, BUFSIZE, fp);
            if (retval == NULL)
            {
                syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
                return;
            }
        }
    
        numfields = strsplit(buffer, fields, 5);
        if (numfields < 5)
        {
            syslog (LOG_ERR, "load: strsplit: error parsing line");
            return;
        }
    
        // fields[0] is "net"
        net_stats.netcnt = atoll(fields[1]);
        net_stats.netudpcnt = atoll(fields[2]);
        net_stats.nettcpcnt = atoll(fields[3]);
        net_stats.nettcpcon = atoll(fields[4]);
    }
    
    if (fclose(fp) != 0)
        syslog (LOG_WARNING, "load: fclose: %s", strerror (errno));

    nfs_net_submit(&net_stats);
}
#undef BUFSIZE

#define BUFSIZE 512
void nfs_rpc_read (void)
{
    FILE *fp;
    char buffer[BUFSIZE];
    nfs_rpc_stats_t rpc_stats; 

    fp = fopen("/proc/net/rpc/nfs", "r");
    if (fp == NULL)
    {
        syslog (LOG_ERR, "load: fopen: %s", strerror(errno));
        return;
    }

    // skip line 1
    {
        char *retval = NULL;
        retval = fgets(buffer, BUFSIZE, fp);
        if (retval == NULL)
        {
            syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
            return;
        }
    }
    
    // line 2: "rpc x x x"
    {
        char *fields[4];
        int numfields = 0;

        {
            char *retval = NULL;
            retval = fgets(buffer, BUFSIZE, fp);
            if (retval == NULL)
            {
                syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
                return;
            }
        }
    
        numfields = strsplit(buffer, fields, 4);
        if (numfields < 4)
        {
            syslog (LOG_ERR, "load: strsplit: error parsing line");
            return;
        }
    
        // fields[0] is "rpc"
        rpc_stats.rpccnt = atoll(fields[1]);
        rpc_stats.rpcretrans = atoll(fields[2]);
        rpc_stats.rpcauthrefresh = atoll(fields[3]);
    }
    
    if (fclose(fp) != 0)
        syslog (LOG_WARNING, "load: fclose: %s", strerror (errno));

    nfs_rpc_submit(&rpc_stats);
}
#undef BUFSIZE

#define BUFSIZE 512
void nfs_v2_read (void)
{
    FILE *fp;
    char buffer[BUFSIZE];
    nfs_v2_stats_t v2_stats; 

    fp = fopen("/proc/net/rpc/nfs", "r");
    if (fp == NULL)
    {
        syslog (LOG_ERR, "load: fopen: %s", strerror(errno));
        return;
    }

    // skip line 1
    {
        char *retval = NULL;
        retval = fgets(buffer, BUFSIZE, fp);
        if (retval == NULL)
        {
            syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
            return;
        }
    }
    
    // skip line 2
    {
        char *retval = NULL;
        retval = fgets(buffer, BUFSIZE, fp);
        if (retval == NULL)
        {
            syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
            return;
        }
    }
    
    // line 3: "proc2 x x x..."
    {
        char *fields[19];
        int numfields = 0;

        {
            char *retval = NULL;
            retval = fgets(buffer, BUFSIZE, fp);
            if (retval == NULL)
            {
                syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
                return;
            }
        }
    
        numfields = strsplit(buffer, fields, 19);
        if (numfields < 4)
        {
            syslog (LOG_ERR, "load: strsplit: error parsing line");
            return;
        }
    
        // fields[0] is "proc2"
        // fields[1] is the number of interface procedures defined for protocol version 2
        v2_stats.v2getattr = atoll(fields[2]);
        v2_stats.v2setattr = atoll(fields[3]);
        v2_stats.v2root = atoll(fields[4]);
        v2_stats.v2lookup = atoll(fields[5]);
        v2_stats.v2readlink = atoll(fields[6]);
        v2_stats.v2read = atoll(fields[7]);
        v2_stats.v2wrcache = atoll(fields[8]);
        v2_stats.v2write = atoll(fields[9]);
        v2_stats.v2create = atoll(fields[10]);
        v2_stats.v2remove = atoll(fields[11]);
        v2_stats.v2rename = atoll(fields[12]);
        v2_stats.v2link = atoll(fields[13]);
        v2_stats.v2symlink = atoll(fields[14]);
        v2_stats.v2mkdir = atoll(fields[15]);
        v2_stats.v2rmdir = atoll(fields[16]);
        v2_stats.v2readdir = atoll(fields[17]);
        v2_stats.v2fsstat = atoll(fields[18]);
    }
    
    if (fclose(fp) != 0)
        syslog (LOG_WARNING, "load: fclose: %s", strerror (errno));

    nfs_v2_submit(&v2_stats);
}
#undef BUFSIZE

#define BUFSIZE 512
void nfs_v3_read (void)
{
    FILE *fp;
    char buffer[BUFSIZE];
    nfs_v3_stats_t v3_stats; 

    fp = fopen("/proc/net/rpc/nfs", "r");
    if (fp == NULL)
    {
        syslog (LOG_ERR, "load: fopen: %s", strerror(errno));
        return;
    }

    // skip line 1
    {
        char *retval = NULL;
        retval = fgets(buffer, BUFSIZE, fp);
        if (retval == NULL)
        {
            syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
            return;
        }
    }
    
    // skip line 2
    {
        char *retval = NULL;
        retval = fgets(buffer, BUFSIZE, fp);
        if (retval == NULL)
        {
            syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
            return;
        }
    }
    
    // skip line 3
    {
        char *retval = NULL;
        retval = fgets(buffer, BUFSIZE, fp);
        if (retval == NULL)
        {
            syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
            return;
        }
    }
    
    // line 4: "proc3 x x x..."
    {
        char *fields[23];
        int numfields = 0;

        {
            char *retval = NULL;
            retval = fgets(buffer, BUFSIZE, fp);
            if (retval == NULL)
            {
                syslog (LOG_ERR, "load: fgets: %s", strerror (errno));
                return;
            }
        }
    
        numfields = strsplit(buffer, fields, 23);
        if (numfields < 4)
        {
            syslog (LOG_ERR, "load: strsplit: error parsing line");
            return;
        }
    
        // fields[0] is "proc3"
        // fields[1] is the number of interface procedures defined for protocol version 3
        v3_stats.v3getattr = atoll(fields[2]);
        v3_stats.v3setattr = atoll(fields[3]);
        v3_stats.v3lookup = atoll(fields[4]);
        v3_stats.v3access = atoll(fields[5]);
        v3_stats.v3readlink = atoll(fields[6]);
        v3_stats.v3read = atoll(fields[7]);
        v3_stats.v3write = atoll(fields[8]);
        v3_stats.v3create = atoll(fields[9]);
        v3_stats.v3mkdir = atoll(fields[10]);
        v3_stats.v3symlink = atoll(fields[11]);
        v3_stats.v3mknod = atoll(fields[12]);
        v3_stats.v3remove = atoll(fields[13]);
        v3_stats.v3rmdir = atoll(fields[14]);
        v3_stats.v3rename = atoll(fields[15]);
        v3_stats.v3link = atoll(fields[16]);
        v3_stats.v3readdir = atoll(fields[17]);
        v3_stats.v3readdirplus = atoll(fields[18]);
        v3_stats.v3fsstat = atoll(fields[19]);
        v3_stats.v3fsinfo = atoll(fields[20]);
        v3_stats.v3pathconf = atoll(fields[21]);
        v3_stats.v3commit = atoll(fields[22]);
    }
    
    if (fclose(fp) != 0)
        syslog (LOG_WARNING, "load: fclose: %s", strerror (errno));

    nfs_v3_submit(&v3_stats);
}
#undef BUFSIZE

void module_register (void)
{
    plugin_register("nfs_net", NULL, nfs_net_read, nfs_net_write);
    plugin_register("nfs_rpc", NULL, nfs_rpc_read, nfs_rpc_write);
    plugin_register("nfs_v2", NULL, nfs_v2_read, nfs_v2_write);
    plugin_register("nfs_v3", NULL, nfs_v3_read, nfs_v3_write);
}

#endif /* COLLECT_LOAD */
-------------- next part --------------
#ifndef NFS_H
#define NFS_H

#include "collectd.h"
#include "common.h"

#ifndef COLLECT_NFS
#if defined(KERNEL_LINUX)
#define COLLECT_NFS 1
#else
#define COLLECT_NFS 0
#endif
#endif /* !defined(COLLECT_NFS) */

#endif /* NFS_H */


More information about the Collectd mailing list