Difference between revisions of "XFCE simple Network Monitor applet"

From ArchWiki
Jump to: navigation, search
(use https for links to archlinux.org)
(request merge)
 
(5 intermediate revisions by 5 users not shown)
Line 1: Line 1:
[[Category:Networking]]
+
[[Category:Internet applications]]
== Introduction ==
+
{{Merge|Xfce|A PKGBUILD for the AUR should also be made and only linked from the section.}}
This little "applet" will add a plain text network monitor for XFCE, without requiring gnome applets support. Unlike the native Xfce netload plugin, this one uses precise plain text figures instead of graphical bars, and also (optionally) reports the CPU usage in percentaje (all system cores). In addition, when placing the mouse over it, it displays a tooltip with extended information. [http://img541.imageshack.us/img541/5049/netmontooltip.png This picture] shows how it looks like. The speed units are automatically selected between kbps and Mbps, formatted in a way that allows to ignore the unit type, difficult to track when the speed changes too quickly (when changing from 999 kbps to 1 Mbps or vice-versa, one becomes immediately aware without needing to look at the kbps/Mbps text).
+
  
== Prerequisites ==
+
The latest and fairly improved version (now not only reports the network activity) has been moved.
  
It runs within the [[https://www.archlinux.org/packages/?q=xfce4-genmon-plugin xfce4-genmon-plugin]]. This implies that it is re-run continuously (typically each second) but this does not causes a performance penalty since it is not an script calling several programs, but a single native C++ application, and the binary will be cached by the system. Since it is executed periodically, it needs to save the state information. By default does it in [[/dev/shm]] (shared memory) to avoid continuous writes on disk. Make sure that your ''/etc/fstab'' file has the following line:
+
Full information and screenshots in [https://github.com/lightful/xfce-hkmon github].
  
shm  /dev/shm  tmpfs  nodev,nosuid  0  0
+
The original version is also available in git history, but the new one it is as simple and easy to install:
  
== Installation ==
+
== Installation instructions ==
  
You need to compile the C++ application: save the following file and run the command '''g++ -O3 -lrt netmon.cpp -o netmon''' to generate the ''netmon'' binary, and place it in a location of your choice (for example, /usr/local/bin).
+
Download [https://raw.githubusercontent.com/lightful/xfce-hkmon/master/xfce-hkmon.cpp xfce-hkmon.cpp] and compile it:
  
{{hc|netmon.cpp|2=
+
g++ -std=c++0x -O3 -lrt xfce-hkmon.cpp -o xfce-hkmon
<nowiki>/*
+
* Copyright (C) 2010 Ciriaco Garcia de Celis
+
*
+
* This program is  free software:  you can redistribute it and/or
+
* modify it under the terms of the  GNU General Public License as
+
* published by the Free Software Foundation,  either version 3 of
+
* the License, or (at your option) any later version.
+
*
+
* This program is distributed in the hope that it will be useful,
+
* but WITHOUT ANY WARRANTY;  without even the implied warranty of
+
* MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the
+
* GNU General Public License (GPL) for more details.
+
*
+
* You should have received a copy of the GNU  GPL along with this
+
* program. If not, see <http://www.gnu.org/licenses/>.
+
*/
+
  
// compile with "g++ -O3 -lrt netmon.cpp -o netmon"
+
Place the executable somewhere (e.g. /usr/local/bin) and add a '''XFCE Generic Monitor Applet''' with these settings: no label, 1 second period, ''Bitstream Vera Sans Mono font'' (recommended) and the following command:
  
#include <sys/stat.h>
+
/usr/local/bin/xfce-hkmon NET CPU TEMP IO RAM
#include <fcntl.h>
+
#include <unistd.h>
+
#include <cstdio>
+
#include <cstring>
+
#include <cstdlib>
+
#include <ctime>
+
#include <climits>
+
  
#define STATE_FILE_BASE "/dev/shm/netmon"
+
You may also add an interface name (eth0, ppp0,...) to override the automatic selection by traffic.
 
+
int exitapp(int exitcode)
+
{
+
    char errmsg[64];
+
    sprintf(errmsg, "ERROR code %d", exitcode);
+
    write(1, errmsg, strlen(errmsg));
+
    return exitcode;
+
}
+
 
+
int main(int argc, char** argv)
+
{
+
    if (argc < 2)
+
    {
+
        printf("usage: %s <network_interface> [CPU]\n", argv[0]);
+
        return 1;
+
    }
+
 
+
    bool reportCPU = (argc > 2) && (strcmp(argv[2], "CPU") == 0);
+
 
+
    char buffer[4096], cad[256], *ni, *nf;
+
   
+
    // read network information
+
    int fd = open("/proc/net/dev", O_RDONLY);
+
    if (fd < 0) return exitapp(2);
+
    int bytes = read(fd, buffer, sizeof(buffer)-1);
+
    close(fd);
+
    if (bytes < 0) return exitapp(3);
+
    buffer[bytes] = 0;
+
 
+
    timespec tp;
+
    clock_gettime(CLOCK_MONOTONIC, &tp);
+
    long long nanoseconds = tp.tv_sec * 1000000000LL + tp.tv_nsec;
+
 
+
    long long recv_bytes=LLONG_MAX, sent_bytes=LLONG_MAX;
+
    bool networkAvailable = false;
+
 
+
    // search for the proper network interface
+
    strcpy(cad, argv[1]);
+
    strcat(cad, ":");
+
    char *pif = strstr(buffer, cad);
+
    if (pif != NULL)
+
    {
+
        networkAvailable = true;
+
 
+
        // jump to the received bytes field
+
        ni = pif + strlen(cad);
+
        while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
+
        for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
+
        *nf++ = 0;
+
 
+
        // get the received bytes
+
        recv_bytes = atoll(ni);
+
 
+
        // jump to the sent bytes field
+
        for (int skip = 0; skip < 8; skip++)
+
        {
+
            ni = nf;
+
            while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
+
            for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
+
            if (!*nf) break;
+
            *nf++ = 0;
+
        }
+
 
+
        // get the sent bytes
+
        sent_bytes = atoll(ni);
+
    }
+
 
+
    long long user_mode_time=0, user_mode_nice_time=0, system_mode_time=0, idle_time=0;
+
 
+
    if (reportCPU)
+
    {
+
        // read CPU information
+
        fd = open("/proc/stat", O_RDONLY);
+
        if (fd < 0) return exitapp(4);
+
        bytes = read(fd, buffer, sizeof(buffer)-1);
+
        close(fd);
+
        if (bytes < 0) return exitapp(5);
+
        buffer[bytes] = 0;
+
 
+
        pif = strstr(buffer, "cpu ");
+
        if (pif != NULL)
+
        {
+
            ni = pif + 3;
+
            while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
+
            for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
+
            *nf++ = 0;
+
 
+
            // get the user mode time
+
            user_mode_time = atoll(ni);
+
 
+
            ni = nf;
+
            while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
+
            for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
+
            *nf++ = 0;
+
 
+
            // get the user mode nice time
+
            user_mode_nice_time = atoll(ni);
+
 
+
            ni = nf;
+
            while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
+
            for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
+
            *nf++ = 0;
+
 
+
            // get the system mode time
+
            system_mode_time = atoll(ni);
+
 
+
            ni = nf;
+
            while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
+
            for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
+
            *nf++ = 0;
+
 
+
            // get the idle time
+
            idle_time = atoll(ni);
+
        }
+
    }
+
 
+
    // read the received/sent bytes, date and CPU usage stored by a previous execution
+
    sprintf(cad, "%s.%s.%d", STATE_FILE_BASE, argv[1], getuid());
+
    fd = open(cad, O_RDWR | O_CREAT, 0664);
+
    if (fd < 0) return exitapp(6);
+
    bytes = read(fd, buffer, sizeof(buffer)-1);
+
    if (bytes < 0)
+
    {
+
        close(fd);
+
        return exitapp(7);
+
    }
+
    long long prev_recv_bytes, prev_sent_bytes, prev_nanoseconds = -1;
+
    long long prev_user_mode_time, prev_user_mode_nice_time, prev_system_mode_time, prev_idle_time = -1;
+
    if (bytes > 0)
+
    {
+
        prev_recv_bytes = atoll(buffer);
+
        prev_sent_bytes = atoll(buffer+20);
+
        prev_nanoseconds = atoll(buffer+40);
+
        prev_user_mode_time = atoll(buffer+60);
+
        prev_user_mode_nice_time = atoll(buffer+80);
+
        prev_system_mode_time = atoll(buffer+100);
+
        prev_idle_time = atoll(buffer+120);
+
    }
+
 
+
    // store in the file the current values for later use
+
    sprintf(buffer, "%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n",
+
        recv_bytes, sent_bytes, nanoseconds,
+
        user_mode_time, user_mode_nice_time, system_mode_time, idle_time);
+
    lseek(fd, 0, SEEK_SET);
+
    write(fd, buffer, 140);
+
    close(fd);
+
 
+
    // generate the result
+
 
+
    strcpy(buffer, "<txt>");
+
 
+
    bool hasNet = networkAvailable && (prev_nanoseconds >= 0) && (recv_bytes >= prev_recv_bytes) && (sent_bytes >= prev_sent_bytes);
+
 
+
    if (!networkAvailable)
+
    {
+
        sprintf(cad, "  %s is down", argv[1]);
+
        strcat(buffer, cad);
+
    }
+
    else if (!hasNet)
+
    {
+
        strcat(buffer, "    ? kbps IN \n    ? kbps OUT");
+
    }
+
    else
+
    {
+
        long long elapsed = nanoseconds - prev_nanoseconds;
+
        if (elapsed < 1) elapsed = 1;
+
        double seconds = elapsed / 1000000000.0;
+
        long long sent = sent_bytes - prev_sent_bytes;
+
        long long received = recv_bytes - prev_recv_bytes;
+
        long inbps = (long) (8 * received / seconds + 999); // adding 999 ensures "1" for any rate above 0
+
        long outbps = (long) (8 * sent / seconds + 999);
+
        if (inbps < 1000000)
+
            sprintf(cad, "%6d kbps IN \n", inbps/1000);
+
        else
+
            sprintf(cad, "%6.3f Mbps IN \n", inbps/1000000.0);
+
        strcat(buffer, cad);
+
 
+
        if (outbps < 1000000)
+
            sprintf(cad, "%6d kbps OUT", outbps/1000);
+
        else
+
            sprintf(cad, "%6.3f Mbps OUT", outbps/1000000.0);
+
        strcat(buffer, cad);
+
       
+
    }
+
 
+
    long long cpu_used = user_mode_time + user_mode_nice_time + system_mode_time
+
                      - (prev_user_mode_time + prev_user_mode_nice_time + prev_system_mode_time);
+
    long long total_cpu = cpu_used + (idle_time - prev_idle_time);
+
    bool hasCPU = (prev_idle_time >= 0) && (total_cpu > 0);
+
    if (reportCPU)
+
    {
+
        if (!hasCPU)
+
        {
+
            strcat(buffer, "\n    ?  % CPU");
+
        }
+
        else
+
        {
+
            sprintf(cad, "\n  %5.1f%% CPU", cpu_used * 100.0 / total_cpu);
+
            strcat(buffer, cad);
+
        }
+
    }
+
 
+
    strcat(buffer, "</txt><tool>");
+
 
+
    if (networkAvailable && hasNet)
+
    {
+
        sprintf(cad, " %s:\n    %.2f MB received \n    %.2f MB sent ",
+
                    argv[1], recv_bytes/1000000.0, sent_bytes/1000000.0);
+
        strcat(buffer, cad);
+
    }
+
 
+
    if (reportCPU && hasCPU)
+
    {
+
        if (networkAvailable && hasNet) strcat(buffer, "\n");
+
        long long total_used_cpu = user_mode_time + user_mode_nice_time + system_mode_time;
+
        sprintf(cad, " CPU usage:\n    %5.1f%% since boot ",
+
                    total_used_cpu * 100.0 / (total_used_cpu + idle_time));
+
        strcat(buffer, cad);
+
    }
+
 
+
    strcat(buffer, "</tool>");
+
 
+
    write(1, buffer, strlen(buffer));
+
 
+
    return 0;
+
}</nowiki>
+
}}
+
 
+
== Configuration ==
+
 
+
Insert in your panel a Generic Monitor applet. In the '''Command''' field place a invocation of the tool, selecting the network interface (eth0, ppp0, wlan0, ...) and optionally add the ''CPU'' parameter to select reporting the CPU usage (the applet will print a third line). For example:
+
 
+
/usr/local/bin/netmon wlan0 CPU
+
 
+
In the '''Period(s)''' field select the refresh rate (1 second recommended). Uncheck the '''Label''' field. An excellent text font is Terminus ([[https://www.archlinux.org/packages/?q=terminus-font terminus-font]] package required) but any monospace, fixed or courier font will be ok.
+
 
+
[http://img812.imageshack.us/img812/8564/netmonsetup.png This picture] resumes the settings. In case of several network interfaces, you can add as many instances as you want.
+

Latest revision as of 12:24, 9 January 2015

Merge-arrows-2.pngThis article or section is a candidate for merging with Xfce.Merge-arrows-2.png

Notes: A PKGBUILD for the AUR should also be made and only linked from the section. (Discuss in Talk:XFCE simple Network Monitor applet#)

The latest and fairly improved version (now not only reports the network activity) has been moved.

Full information and screenshots in github.

The original version is also available in git history, but the new one it is as simple and easy to install:

Installation instructions

Download xfce-hkmon.cpp and compile it:

g++ -std=c++0x -O3 -lrt xfce-hkmon.cpp -o xfce-hkmon

Place the executable somewhere (e.g. /usr/local/bin) and add a XFCE Generic Monitor Applet with these settings: no label, 1 second period, Bitstream Vera Sans Mono font (recommended) and the following command:

/usr/local/bin/xfce-hkmon NET CPU TEMP IO RAM

You may also add an interface name (eth0, ppp0,...) to override the automatic selection by traffic.