Merge pull request #2232 from rpv-tomsk/processes
authorFlorian Forster <ff@octo.it>
Thu, 20 Jul 2017 06:14:17 +0000 (08:14 +0200)
committerGitHub <noreply@github.com>
Thu, 20 Jul 2017 06:14:17 +0000 (08:14 +0200)
processes: Show real disk IO in addition to process IO (Linux only)

1  2 
src/processes.c
src/types.db

diff --combined src/processes.c
@@@ -185,6 -185,8 +185,8 @@@ typedef struct process_entry_s 
    derive_t io_wchar;
    derive_t io_syscr;
    derive_t io_syscw;
+   derive_t io_diskr;
+   derive_t io_diskw;
    _Bool has_io;
  
    derive_t cswitch_vol;
@@@ -209,6 -211,8 +211,8 @@@ typedef struct procstat_entry_s 
    derive_t io_wchar;
    derive_t io_syscr;
    derive_t io_syscw;
+   derive_t io_diskr;
+   derive_t io_diskw;
  
    derive_t cswitch_vol;
    derive_t cswitch_invol;
@@@ -242,6 -246,8 +246,8 @@@ typedef struct procstat 
    derive_t io_wchar;
    derive_t io_syscr;
    derive_t io_syscw;
+   derive_t io_diskr;
+   derive_t io_diskw;
  
    derive_t cswitch_vol;
    derive_t cswitch_invol;
@@@ -302,7 -308,7 +308,7 @@@ static procstat_t *ps_list_register(con
    new = calloc(1, sizeof(*new));
    if (new == NULL) {
      ERROR("processes plugin: ps_list_register: calloc failed.");
 -    return (NULL);
 +    return NULL;
    }
    sstrncpy(new->name, name, sizeof(new->name));
  
    new->io_wchar = -1;
    new->io_syscr = -1;
    new->io_syscw = -1;
+   new->io_diskr = -1;
+   new->io_diskw = -1;
    new->cswitch_vol = -1;
    new->cswitch_invol = -1;
  
      if (new->re == NULL) {
        ERROR("processes plugin: ps_list_register: malloc failed.");
        sfree(new);
 -      return (NULL);
 +      return NULL;
      }
  
      status = regcomp(new->re, regexp, REG_EXTENDED | REG_NOSUB);
              regexp);
        sfree(new->re);
        sfree(new);
 -      return (NULL);
 +      return NULL;
      }
    }
  #else
            "has been disabled at compile time.",
            regexp);
      sfree(new);
 -    return (NULL);
 +    return NULL;
    }
  #endif
  
        sfree(new->re);
  #endif
        sfree(new);
 -      return (NULL);
 +      return NULL;
      }
  
      if (ptr->next == NULL)
    else
      ptr->next = new;
  
 -  return (new);
 +  return new;
  } /* void ps_list_register */
  
  /* try to match name against entry, returns 1 if success */
@@@ -393,13 -401,13 +401,13 @@@ static int ps_list_match(const char *na
                       /* pmatch = */ NULL,
                       /* eflags = */ 0);
      if (status == 0)
 -      return (1);
 +      return 1;
    } else
  #endif
        if (strcmp(ps->name, name) == 0)
 -    return (1);
 +    return 1;
  
 -  return (0);
 +  return 0;
  } /* int ps_list_match */
  
  static void ps_update_counter(derive_t *group_counter, derive_t *curr_counter,
@@@ -480,6 -488,11 +488,11 @@@ static void ps_list_add(const char *nam
        ps_update_counter(&ps->io_syscw, &pse->io_syscw, entry->io_syscw);
      }
  
+     if ((entry->io_diskr != -1) && (entry->io_diskw != -1)) {
+       ps_update_counter(&ps->io_diskr, &pse->io_diskr, entry->io_diskr);
+       ps_update_counter(&ps->io_diskw, &pse->io_diskw, entry->io_diskw);
+     }
      if ((entry->cswitch_vol != -1) && (entry->cswitch_vol != -1)) {
        ps_update_counter(&ps->cswitch_vol, &pse->cswitch_vol,
                          entry->cswitch_vol);
@@@ -614,7 -627,7 +627,7 @@@ static int ps_config(oconfig_item_t *ci
      }
    }
  
 -  return (0);
 +  return 0;
  }
  
  static int ps_init(void) {
      ERROR("host_processor_sets failed: %s\n", mach_error_string(status));
      pset_list = NULL;
      pset_list_len = 0;
 -    return (-1);
 +    return -1;
    }
  /* #endif HAVE_THREAD_INFO */
  
    pagesize = getpagesize();
  #endif /* HAVE_PROCINFO_H */
  
 -  return (0);
 +  return 0;
  } /* int ps_init */
  
  /* submit global state (e.g.: qty of zombies, running, etc..) */
@@@ -725,7 -738,7 +738,7 @@@ static void ps_submit_proc_list(procsta
    plugin_dispatch_values(&vl);
  
    if ((ps->io_rchar != -1) && (ps->io_wchar != -1)) {
-     sstrncpy(vl.type, "ps_disk_octets", sizeof(vl.type));
+     sstrncpy(vl.type, "io_octets", sizeof(vl.type));
      vl.values[0].derive = ps->io_rchar;
      vl.values[1].derive = ps->io_wchar;
      vl.values_len = 2;
    }
  
    if ((ps->io_syscr != -1) && (ps->io_syscw != -1)) {
-     sstrncpy(vl.type, "ps_disk_ops", sizeof(vl.type));
+     sstrncpy(vl.type, "io_ops", sizeof(vl.type));
      vl.values[0].derive = ps->io_syscr;
      vl.values[1].derive = ps->io_syscw;
      vl.values_len = 2;
      plugin_dispatch_values(&vl);
    }
  
+   if ((ps->io_diskr != -1) && (ps->io_diskw != -1)) {
+     sstrncpy(vl.type, "disk_octets", sizeof(vl.type));
+     vl.values[0].derive = ps->io_diskr;
+     vl.values[1].derive = ps->io_diskw;
+     vl.values_len = 2;
+     plugin_dispatch_values(&vl);
+   }
    if (ps->num_fd > 0) {
      sstrncpy(vl.type, "file_handles", sizeof(vl.type));
      vl.values[0].gauge = ps->num_fd;
          "cpu_user_counter = %" PRIi64 "; cpu_system_counter = %" PRIi64 "; "
          "io_rchar = %" PRIi64 "; io_wchar = %" PRIi64 "; "
          "io_syscr = %" PRIi64 "; io_syscw = %" PRIi64 "; "
+         "io_diskr = %" PRIi64 "; io_diskw = %" PRIi64 "; "
          "cswitch_vol = %" PRIi64 "; cswitch_invol = %" PRIi64 ";",
          ps->name, ps->num_proc, ps->num_lwp, ps->num_fd, ps->vmem_size,
          ps->vmem_rss, ps->vmem_data, ps->vmem_code, ps->vmem_minflt_counter,
          ps->vmem_majflt_counter, ps->cpu_user_counter, ps->cpu_system_counter,
-         ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw, ps->cswitch_vol,
-         ps->cswitch_invol);
+         ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw, ps->io_diskr,
+         ps->io_diskw, ps->cswitch_vol, ps->cswitch_invol);
  } /* void ps_submit_proc_list */
  
  #if KERNEL_LINUX || KERNEL_SOLARIS
@@@ -805,11 -827,11 +827,11 @@@ static int ps_read_tasks_status(process
    char *fields[8];
    int numfields;
  
 -  ssnprintf(dirname, sizeof(dirname), "/proc/%li/task", ps->id);
 +  snprintf(dirname, sizeof(dirname), "/proc/%li/task", ps->id);
  
    if ((dh = opendir(dirname)) == NULL) {
      DEBUG("Failed to open directory `%s'", dirname);
 -    return (-1);
 +    return -1;
    }
  
    while ((ent = readdir(dh)) != NULL) {
  
      tpid = ent->d_name;
  
 -    ssnprintf(filename, sizeof(filename), "/proc/%li/task/%s/status", ps->id,
 -              tpid);
 +    if (snprintf(filename, sizeof(filename), "/proc/%li/task/%s/status", ps->id,
 +                 tpid) >= sizeof(filename)) {
 +      DEBUG("Filename too long: `%s'", filename);
 +      continue;
 +    }
 +
      if ((fh = fopen(filename, "r")) == NULL) {
        DEBUG("Failed to open file `%s'", filename);
        continue;
    ps->cswitch_vol = cswitch_vol;
    ps->cswitch_invol = cswitch_invol;
  
 -  return (0);
 +  return 0;
  } /* int *ps_read_tasks_status */
  
  /* Read data from /proc/pid/status */
@@@ -882,9 -900,9 +904,9 @@@ static int ps_read_status(long pid, pro
    char *fields[8];
    int numfields;
  
 -  ssnprintf(filename, sizeof(filename), "/proc/%li/status", pid);
 +  snprintf(filename, sizeof(filename), "/proc/%li/status", pid);
    if ((fh = fopen(filename, "r")) == NULL)
 -    return (-1);
 +    return -1;
  
    while (fgets(buffer, sizeof(buffer), fh) != NULL) {
      unsigned long tmp;
    if (threads != 0)
      ps->num_lwp = threads;
  
 -  return (0);
 +  return 0;
  } /* int *ps_read_status */
  
  static int ps_read_io(process_entry_t *ps) {
    char *fields[8];
    int numfields;
  
 -  ssnprintf(filename, sizeof(filename), "/proc/%li/io", ps->id);
 +  snprintf(filename, sizeof(filename), "/proc/%li/io", ps->id);
    if ((fh = fopen(filename, "r")) == NULL) {
      DEBUG("ps_read_io: Failed to open file `%s'", filename);
 -    return (-1);
 +    return -1;
    }
  
    while (fgets(buffer, sizeof(buffer), fh) != NULL) {
        val = &(ps->io_syscr);
      else if (strncasecmp(buffer, "syscw:", 6) == 0)
        val = &(ps->io_syscw);
+     else if (strncasecmp(buffer, "read_bytes:", 11) == 0)
+       val = &(ps->io_diskr);
+     else if (strncasecmp(buffer, "write_bytes:", 12) == 0)
+       val = &(ps->io_diskw);
      else
        continue;
  
      char errbuf[1024];
      WARNING("processes: fclose: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
    }
 -  return (0);
 +  return 0;
  } /* int ps_read_io (...) */
  
  static int ps_count_fd(int pid) {
    struct dirent *ent;
    int count = 0;
  
 -  ssnprintf(dirname, sizeof(dirname), "/proc/%i/fd", pid);
 +  snprintf(dirname, sizeof(dirname), "/proc/%i/fd", pid);
  
    if ((dh = opendir(dirname)) == NULL) {
      DEBUG("Failed to open directory `%s'", dirname);
 -    return (-1);
 +    return -1;
    }
    while ((ent = readdir(dh)) != NULL) {
      if (!isdigit((int)ent->d_name[0]))
    }
    closedir(dh);
  
 -  return ((count >= 1) ? count : 1);
 +  return (count >= 1) ? count : 1;
  } /* int ps_count_fd (pid) */
  
  static void ps_fill_details(const procstat_t *ps, process_entry_t *entry) {
@@@ -1045,11 -1067,11 +1071,11 @@@ static int ps_read_process(long pid, pr
  
    ssize_t status;
  
 -  ssnprintf(filename, sizeof(filename), "/proc/%li/stat", pid);
 +  snprintf(filename, sizeof(filename), "/proc/%li/stat", pid);
  
    status = read_file_contents(filename, buffer, sizeof(buffer) - 1);
    if (status <= 0)
 -    return (-1);
 +    return -1;
    buffer_len = (size_t)status;
    buffer[buffer_len] = 0;
  
    if (name_start_pos >= name_end_pos) {
      ERROR("processes plugin: name_start_pos = %zu >= name_end_pos = %zu",
            name_start_pos, name_end_pos);
 -    return (-1);
 +    return -1;
    }
  
    name_len = (name_end_pos - name_start_pos) - 1;
    sstrncpy(ps->name, &buffer[name_start_pos + 1], name_len + 1);
  
    if ((buffer_len - name_end_pos) < 2)
 -    return (-1);
 +    return -1;
    buffer_ptr = &buffer[name_end_pos + 2];
  
    fields_len = strsplit(buffer_ptr, fields, STATIC_ARRAY_SIZE(fields));
      DEBUG("processes plugin: ps_read_process (pid = %li):"
            " `%s' has only %i fields..",
            pid, filename, fields_len);
 -    return (-1);
 +    return -1;
    }
  
    *state = fields[0][0];
      DEBUG("processes plugin: This is only a zombie: pid = %li; "
            "name = %s;",
            pid, ps->name);
 -    return (0);
 +    return 0;
    }
  
    cpu_user_counter = atoll(fields[11]);
    ps->io_wchar = -1;
    ps->io_syscr = -1;
    ps->io_syscw = -1;
+   ps->io_diskr = -1;
+   ps->io_diskw = -1;
  
    ps->cswitch_vol = -1;
    ps->cswitch_invol = -1;
  
    /* success */
 -  return (0);
 +  return 0;
  } /* int ps_read_process (...) */
  
  static char *ps_get_cmdline(long pid, char *name, char *buf, size_t buf_len) {
    if ((pid < 1) || (NULL == buf) || (buf_len < 2))
      return NULL;
  
 -  ssnprintf(file, sizeof(file), "/proc/%li/cmdline", pid);
 +  snprintf(file, sizeof(file), "/proc/%li/cmdline", pid);
  
    errno = 0;
    fd = open(file, O_RDONLY);
      if (NULL == name)
        return NULL;
  
 -    ssnprintf(buf, buf_len, "[%s]", name);
 +    snprintf(buf, buf_len, "[%s]", name);
      return buf;
    }
  
@@@ -1261,7 -1285,7 +1289,7 @@@ static int read_fork_rate(void) 
      char errbuf[1024];
      ERROR("processes plugin: fopen (/proc/stat) failed: %s",
            sstrerror(errno, errbuf, sizeof(errbuf)));
 -    return (-1);
 +    return -1;
    }
  
    while (fgets(buffer, sizeof(buffer), proc_stat) != NULL) {
    fclose(proc_stat);
  
    if (!value_valid)
 -    return (-1);
 +    return -1;
  
    ps_submit_fork_rate(value.derive);
 -  return (0);
 +  return 0;
  }
  #endif /*KERNEL_LINUX */
  
@@@ -1308,13 -1332,13 +1336,13 @@@ static char *ps_get_cmdline(long pid
            "while reading \"%s\": "
            "Returned %zd but expected %zu.",
            path, status, buffer_size);
 -    return (NULL);
 +    return NULL;
    }
  
    info.pr_psargs[sizeof(info.pr_psargs) - 1] = 0;
    sstrncpy(buffer, info.pr_psargs, buffer_size);
  
 -  return (buffer);
 +  return buffer;
  } /* }}} int ps_get_cmdline */
  
  /*
@@@ -1359,7 -1383,7 +1387,7 @@@ static int ps_read_process(long pid, pr
      sfree(myStatus);
      sfree(myInfo);
      sfree(myUsage);
 -    return (0);
 +    return 0;
    } else {
      ps->num_proc = 1;
      ps->num_lwp = myInfo->pr_nlwp;
    ps->io_wchar = myUsage->pr_oublk * chars_per_block;
    ps->io_syscr = myUsage->pr_sysc;
    ps->io_syscw = myUsage->pr_sysc;
+   ps->io_diskr = -1;
+   ps->io_diskw = -1;
  
    /*
     * TODO: context switch counters for Solaris
    sfree(myInfo);
    sfree(myUsage);
  
 -  return (0);
 +  return 0;
  }
  
  /*
@@@ -1449,7 -1475,7 +1479,7 @@@ static int read_fork_rate(void) 
    derive_t result = 0;
  
    if (kc == NULL)
 -    return (-1);
 +    return -1;
  
    for (kstat_t *ksp_chain = kc->kc_chain; ksp_chain != NULL;
         ksp_chain = ksp_chain->ks_next) {
    }
  
    ps_submit_fork_rate(result);
 -  return (0);
 +  return 0;
  }
  #endif /* KERNEL_SOLARIS */
  
@@@ -1484,12 -1510,12 +1514,12 @@@ static int mach_get_task_name(task_t t
    mib[2] = KERN_PROC_PID;
  
    if (pid_for_task(t, pid) != KERN_SUCCESS)
 -    return (-1);
 +    return -1;
    mib[3] = *pid;
  
    kp_size = sizeof(kp);
    if (sysctl(mib, 4, &kp, &kp_size, NULL, 0) != 0)
 -    return (-1);
 +    return -1;
  
    if (name_max_len > (MAXCOMLEN + 1))
      name_max_len = MAXCOMLEN + 1;
     * `top' does it, because it is a lot of work and only used when
     * debugging. -octo */
  
 -  return (0);
 +  return 0;
  }
  #endif /* HAVE_THREAD_INFO */
  /* ------- end of additional functions for KERNEL_LINUX/HAVE_THREAD_INFO -------
@@@ -1620,6 -1646,8 +1650,8 @@@ static int ps_read(void) 
          pse.io_wchar = -1;
          pse.io_syscr = -1;
          pse.io_syscw = -1;
+         pse.io_diskr = -1;
+         pse.io_diskw = -1;
  
          /* File descriptor count not implemented */
          pse.num_fd = 0;
    if ((proc = opendir("/proc")) == NULL) {
      char errbuf[1024];
      ERROR("Cannot open `/proc': %s", sstrerror(errno, errbuf, sizeof(errbuf)));
 -    return (-1);
 +    return -1;
    }
  
    while ((ent = readdir(proc)) != NULL) {
    kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf);
    if (kd == NULL) {
      ERROR("processes plugin: Cannot open kvm interface: %s", errbuf);
 -    return (0);
 +    return 0;
    }
  
    /* Get the list of processes. */
      ERROR("processes plugin: Cannot get kvm processes list: %s",
            kvm_geterr(kd));
      kvm_close(kd);
 -    return (0);
 +    return 0;
    }
  
    /* Iterate through the processes in kinfo_proc */
        pse.io_wchar = -1;
        pse.io_syscr = -1;
        pse.io_syscw = -1;
+       pse.io_diskr = -1;
+       pse.io_diskw = -1;
  
        /* file descriptor count not implemented */
        pse.num_fd = 0;
    kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
    if (kd == NULL) {
      ERROR("processes plugin: Cannot open kvm interface: %s", errbuf);
 -    return (0);
 +    return 0;
    }
  
    /* Get the list of processes. */
      ERROR("processes plugin: Cannot get kvm processes list: %s",
            kvm_geterr(kd));
      kvm_close(kd);
 -    return (0);
 +    return 0;
    }
  
    /* Iterate through the processes in kinfo_proc */
        pse.io_wchar = -1;
        pse.io_syscr = -1;
        pse.io_syscw = -1;
+       pse.io_diskr = -1;
+       pse.io_diskw = -1;
  
        /* file descriptor count not implemented */
        pse.num_fd = 0;
        pse.io_wchar = -1;
        pse.io_syscr = -1;
        pse.io_syscw = -1;
+       pse.io_diskr = -1;
+       pse.io_diskw = -1;
  
        pse.num_fd = 0;
  
  
    proc = opendir("/proc");
    if (proc == NULL)
 -    return (-1);
 +    return -1;
  
    while ((ent = readdir(proc)) != NULL) {
      long pid;
  
    want_init = 0;
  
 -  return (0);
 +  return 0;
  } /* int ps_read */
  
  void module_register(void) {
diff --combined src/types.db
@@@ -26,7 -26,7 +26,7 @@@ clock_last_meas         value:GAUGE:0:
  clock_last_update       value:GAUGE:U:U
  clock_mode              value:GAUGE:0:U
  clock_reachability      value:GAUGE:0:U
 -clock_skew_ppm          value:GAUGE:-2:2
 +clock_skew_ppm          value:GAUGE:0:1000000
  clock_state             value:GAUGE:0:U
  clock_stratum           value:GAUGE:0:U
  compression             uncompressed:DERIVE:0:U, compressed:DERIVE:0:U
@@@ -37,7 -37,6 +37,7 @@@ contextswitch           value:DERIVE:0:
  count                   value:GAUGE:0:U
  counter                 value:COUNTER:U:U
  cpu                     value:DERIVE:0:U
 +cpu_affinity            value:GAUGE:0:1
  cpufreq                 value:GAUGE:0:U
  current                 value:GAUGE:U:U
  current_connections     value:GAUGE:0:U
@@@ -48,7 -47,6 +48,7 @@@ df                      used:GAUGE:0:11
  df_complex              value:GAUGE:0:U
  df_inodes               value:GAUGE:0:U
  dilution_of_precision   value:GAUGE:0:U
 +disk_error              value:GAUGE:0:U
  disk_io_time            io_time:DERIVE:0:U, weighted_io_time:DERIVE:0:U
  disk_latency            read:GAUGE:0:U, write:GAUGE:0:U
  disk_merged             read:DERIVE:0:U, write:DERIVE:0:U
@@@ -72,7 -70,6 +72,7 @@@ dns_response            value:DERIVE:0:
  dns_transfer            value:DERIVE:0:U
  dns_update              value:DERIVE:0:U
  dns_zops                value:DERIVE:0:U
 +domain_state            state:GAUGE:0:U, reason:GAUGE:0:U
  drbd_resource           value:DERIVE:0:U
  duration                seconds:GAUGE:0:U
  email_check             value:GAUGE:0:U
@@@ -92,7 -89,7 +92,7 @@@ filter_result           value:DERIVE:0:
  flow                    value:GAUGE:0:U
  fork_rate               value:DERIVE:0:U
  frequency               value:GAUGE:0:U
 -frequency_error         value:GAUGE:-2:2 
 +frequency_error         value:GAUGE:-1000000:1000000
  frequency_offset        value:GAUGE:-1000000:1000000
  fscache_stat            value:DERIVE:0:U
  gauge                   value:GAUGE:U:U
@@@ -117,12 -114,12 +117,13 @@@ if_tx_octets            value:DERIVE:0:
  if_tx_packets           value:DERIVE:0:U
  invocations             value:DERIVE:0:U
  io_octets               rx:DERIVE:0:U, tx:DERIVE:0:U
+ io_ops                  read:DERIVE:0:U, write:DERIVE:0:U
  io_packets              rx:DERIVE:0:U, tx:DERIVE:0:U
  ipc                     value:GAUGE:0:U
  ipt_bytes               value:DERIVE:0:U
  ipt_packets             value:DERIVE:0:U
  irq                     value:DERIVE:0:U
 +job_stats               value:DERIVE:0:U
  latency                 value:GAUGE:0:U
  links                   value:GAUGE:0:U
  load                    shortterm:GAUGE:0:5000, midterm:GAUGE:0:5000, longterm:GAUGE:0:5000
@@@ -172,7 -169,6 +173,7 @@@ pending_operations      value:GAUGE:0:
  percent                 value:GAUGE:0:100.1
  percent_bytes           value:GAUGE:0:100.1
  percent_inodes          value:GAUGE:0:100.1
 +perf                    value:DERIVE:0:U
  pf_counters             value:DERIVE:0:U
  pf_limits               value:DERIVE:0:U
  pf_source               value:DERIVE:0:U