/* * IL.C: IsdnLog analysis tool for Traverse Technologies Netjet ISDN card * * (C) 1999 Marc Durdin * * Version 0.1.2: added actual date/times to text display * * Version 0.1.1: fixed some rounding problems... * * Version 0.1: Initial release * * 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 2 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #define LOG_PATH "/var/log/isdn/ild/" #define LOG_WILDCARD "*.log" #define HTML_PATH "./" #define CHANNEL_BYTES 8192 /* Theoretical maximum throughput on one ISDN channel per second in bytes */ #define STEP_FOREVER -1 #define STEP_MONTH (28*24*60*60) #define STEP_DAY (24*60*60) #define STEP_HOUR (60*60) #define STEP_MINUTE (60) #define COUNT_MONTH 4 #define COUNT_DAY 120 #define COUNT_HOUR 168 #define COUNT_MINUTE 512 #define GIFX 480 #define GIFY 220 void display_usage(void); double factor(struct stat *s); int get_num_channels(void); int parse_params(int argc, char *argv[]); int prepare_buffers(void); void free_buffers(void); void init_starts(void); void generate_stats(void); void generate_stats_file(char *filename); void add_stat(time_t tm, int rec, int snd); void display_gif(void); void display_html(void); void display_tty(void); void print_stats(FILE *hdl, struct stat *s); void print_stats_forever(FILE *hdl, struct stat *s); void make_gif(const char *path, struct stat *s, int sr); char *get_stat_name(struct stat *s); struct stat { int use; int step; time_t start; double *recd, *sndd; }; int write_html, write_tty, write_gif; struct stat *stat; //forever, *month, *day, *hour, *minute; int num_stat; //int num_month, num_day, num_hour, num_minute; time_t current_time; int num_channels, max_utilisation; int gif_x, gif_y; char html_path[256], log_path[256]; void main(int argc, char *argv[]) { if(!parse_params(argc, argv)) { display_usage(); return; } get_num_channels(); if(!prepare_buffers()) return; init_starts(); generate_stats(); if(write_tty) display_tty(); if(write_html) display_html(); if(write_gif) display_gif(); free_buffers(); } void display_usage(void) { printf("IL: IsdnLog analysis tool for Traverse Technologies Netjet ISDN card\n\n"); printf("Usage: IL -ohtg [output] [options]\n\n"); printf(" -ohtg [h]TML, [t]TY, [g]IF output\n"); printf("output: one or more of (can be repeated)\n"); printf(" -F report total usage\n"); printf(" -Mx report usage for last x months [%d]\n", COUNT_MONTH); printf(" -Dx report usage for last x days [%d]\n", COUNT_DAY); printf(" -Hx report usage for last x hours [%d]\n", COUNT_HOUR); printf(" -mx report usage for last x minutes [%d]\n", COUNT_MINUTE); printf("options: -lpath source log path [%s]\n", LOG_PATH); printf(" -hpath write HTML to path [%s]\n", HTML_PATH); printf(" -dXxY set GIF dimensions to X*Y [%dx%d]\n", GIFX, GIFY); } /*************************** Initialisation functions ****************************/ int get_num_channels(void) { FILE *fp; char str[512], *p; if((fp = fopen("/dev/isdninfo", "rt")) == NULL) return 0; if(!fp) exit(1); fgets(str, 512, fp); fclose(fp); if((p = strchr(str, ':')) == NULL) return 0; p = strtok(p + 1, " "); num_channels = 0; while(p[0] != '-') { num_channels++; p = strtok(NULL, " "); } max_utilisation = CHANNEL_BYTES * num_channels; return num_channels; } char *options = "o:FM::D::H::m::h:d:l:"; void alloc_stat(int step, int use) { struct stat *st; int i; st = malloc(sizeof(struct stat) * ++num_stat); for(i = 0; i < num_stat - 1; i++) st[i] = stat[i]; if(stat) free(stat); stat = st; stat[num_stat-1].step = step; stat[num_stat-1].use = use; } int parse_params(int argc, char *argv[]) { char *s; int c; write_html = 0; write_tty = 0; write_gif = 0; num_stat = 0; stat = NULL; gif_x = GIFX; gif_y = GIFY; strcpy(html_path, HTML_PATH); strcpy(log_path, LOG_PATH); while((c = getopt(argc, argv, options)) != EOF) switch(c) { case 'o': write_html = (int) strchr(optarg, 'h'); write_tty = (int) strchr(optarg, 't'); write_gif = (int) strchr(optarg, 'g'); break; case 'F': alloc_stat(STEP_FOREVER, 1); break; case 'M': alloc_stat(STEP_MONTH, optarg ? atoi(optarg) : COUNT_MONTH); break; case 'D': alloc_stat(STEP_DAY, optarg ? atoi(optarg) : COUNT_DAY); break; case 'H': alloc_stat(STEP_HOUR, optarg ? atoi(optarg) : COUNT_HOUR); break; case 'm': alloc_stat(STEP_MINUTE, optarg ? atoi(optarg) : COUNT_MINUTE); break; case 'h': strcpy(html_path, optarg); break; case 'l': strcpy(log_path, optarg); break; case 'd': gif_x = strtol(optarg, &s, 10); gif_y = strtol(s+1, NULL, 10); break; default: return 0; } return (write_html|write_tty|write_gif) && num_stat; } void pbuf_alloc(struct stat *s) { int i; if(s->use) { s->recd = (double *)malloc(sizeof(double) * s->use); s->sndd = (double *)malloc(sizeof(double) * s->use); for(i = 0; i < s->use; i++) { s->recd[i] = 0; s->sndd[i] = 0; } } else { s->recd = NULL; s->sndd = NULL; } } void pbuf_free(struct stat *s) { if(s->use) { free((void *)s->recd); free((void *)s->sndd); } s->recd = NULL; s->sndd = NULL; } int prepare_buffers(void) { int i; for(i = 0; i < num_stat; i++) pbuf_alloc(&stat[i]); } void free_buffers(void) { int i; for(i = 0; i < num_stat; i++) pbuf_free(&stat[i]); free(stat); stat = NULL; } void init_starts(void) { int i; time_t base_time; struct tm tm = {0}; time(¤t_time); tm.tm_year = 90; tm.tm_mday = 1; base_time = mktime(&tm); for(i = 0; i < num_stat; i++) if(stat[i].step == STEP_FOREVER) stat[i].start = 0; else { stat[i].start = current_time - stat[i].step * stat[i].use; stat[i].start -= ((stat[i].start-base_time) % stat[i].step) - stat[i].step; //stat[i].start += stat[i].step; } } /*************************** Statistic collation functions ****************************/ void generate_stats(void) { glob_t globbuf; int i; char str[256]; globbuf.gl_offs = 0; sprintf(str, "%s%s", log_path, LOG_WILDCARD); glob(str, 0, NULL, &globbuf); for(i = 0; i < globbuf.gl_pathc; i++) { generate_stats_file(globbuf.gl_pathv[i]); } globfree(&globbuf); } void generate_stats_file(char *filename) { time_t tm; int rec, snd; FILE *fp; char str[128], *s; fp = fopen(filename, "rt"); while(fgets(str, 128, fp)) { tm = strtoul(str, &s, 10) * 60; // time in seconds rec = strtol(s, &s, 10); // bytes recv in that minute snd = strtol(s, &s, 10); // bytes sent in that minute if(tm > 0) add_stat(tm, rec, snd); } fclose(fp); } void add_stat(time_t tm, int rec, int snd) { int x, i; for(i = 0; i < num_stat; i++) { if(stat[i].step == STEP_FOREVER) { if(stat[i].start == 0 || stat[i].start > tm) stat[i].start = tm; stat[i].recd[0] += rec; stat[i].sndd[0] += snd; } else if(tm >= stat[i].start) { x = (tm - stat[i].start)/stat[i].step; stat[i].recd[x] += rec; stat[i].sndd[x] += snd; } } } /*************************** Display functions ****************************/ char *get_stat_name(struct stat *s) { switch(s->step) { case STEP_FOREVER: return "Forever"; case STEP_MONTH: return "Month"; case STEP_DAY: return "Day"; case STEP_HOUR: return "Hour"; case STEP_MINUTE: return "Minute"; default: return "?"; } } double utilisation(double amount, struct stat *s) { return (amount * 100.0/((double)max_utilisation * factor(s))); } char *get_path(char *path, char *filename, char *buf) { char *p; if(*path != 0) { p = strchr(strcpy(buf, path), 0); p--; if(*p != '/') strcat(buf, "/"); strcat(buf, filename); } else strcpy(buf, filename); return buf; } void display_tty(void) { int i; fprintf(stdout, "Current date/time: %s\n", ctime(¤t_time)); for(i = 0; i < num_stat; i++) { if(stat[i].step == STEP_FOREVER) print_stats_forever(stdout, &stat[i]); else print_stats(stdout, &stat[i]); } } void display_html(void) { FILE *fp; char str[256]; int i; if((fp = fopen(get_path(html_path, "index.html", str), "w")) == NULL) return; fprintf(fp, "ISDN Statistics\n"); if(write_gif) fprintf(fp, "See graphs of statistics

\n"); fprintf(fp, "

"); fprintf(fp, "

\n");

    fprintf(fp, "Current date/time: %s\n", ctime(¤t_time));
    
    for(i = 0; i < num_stat; i++)
    {
        if(stat[i].step == STEP_FOREVER) print_stats_forever(fp, &stat[i]);
        else print_stats(fp, &stat[i]);
    }

    fprintf(fp, "\n
\n"); fclose(fp); } void display_gif(void) { FILE *fp; int i; char nms[32], nmr[32], str[256], *p; if((fp = fopen(get_path(html_path, "graph.html", str), "w")) == NULL) return; fprintf(fp, "ISDN Statistics\n"); if(write_html) fprintf(fp, "See text statistics

\n"); fprintf(fp, "

"); fprintf(fp, "Current date/time: %s\n", ctime(¤t_time)); for(i = 0; i < num_stat; i++) { p = get_stat_name(&stat[i]); sprintf(nmr, "%dr.gif", i); sprintf(nms, "%ds.gif", i); if(stat[i].step == STEP_FOREVER) fprintf(fp, "

Cumulative statistics

 

\n", nmr, nms); else fprintf(fp, "

Last %d %s statistics

 

\n", stat[i].use, p, nmr, nms); make_gif(get_path(html_path, nmr, str), &stat[i], 1); make_gif(get_path(html_path, nms, str), &stat[i], 2); } fprintf(fp, "\n"); fclose(fp); } void print_stats_forever(FILE *hdl, struct stat *s) { fprintf(hdl, "Statistics for ISDN forever\n"); fprintf(hdl, "===========================\n\n"); fprintf(hdl, "First use of log was: %s\n", ctime(&s->start)); fprintf(hdl, "KBytes received: %8.0f (%.2f%%) %.0f\n", s->recd[0]/1024, utilisation(s->recd[0], s), factor(s)); fprintf(hdl, "KBytes sent: %8.0f (%.2f%%) %.0f\n\n", s->sndd[0]/1024, utilisation(s->sndd[0], s), factor(s)); } void print_stats(FILE *hdl, struct stat *s) { int i; char s2[20], ss[16]; time_t t; struct tm *tm; fprintf(hdl, "Statistics for last %2d %s(s)\n", s->use, get_stat_name(s)); fprintf(hdl, "--------------------------------\n\n"); fprintf(hdl, "Start date/time: %s\n\n", ctime(&s->start)); switch(s->step) // set width of first column { case STEP_MONTH: i = 5; break; case STEP_DAY: i = 5; break; case STEP_HOUR: i = 8; break; case STEP_MINUTE: i = 5; break; } i += 7; fprintf(hdl, "%*.*s | KB Received | %% | KB Sent | %% |\n", i-1, i-1, get_stat_name(s)); s2[i--] = 0; while(i>=0) s2[i--] = '-'; fprintf(hdl, "%s.-------------.--------.-------------.--------. \n", s2); for(i = 0; i < s->use; i++) { t = (s->start + (i * s->step)); tm = localtime(&t); switch(s->step) { case STEP_MONTH: sprintf(ss, "%2d-%02d", tm->tm_mday, tm->tm_mon+1); break; case STEP_DAY: sprintf(ss, "%2d-%02d", tm->tm_mday, tm->tm_mon+1); break; case STEP_HOUR: sprintf(ss, "%02d %2d:%02d", tm->tm_mday, tm->tm_hour, tm->tm_min); break; case STEP_MINUTE: sprintf(ss, "%2d:%02d", tm->tm_hour, tm->tm_min); break; } fprintf(hdl, " %3d %s | %11.0f | % 6.2f | %11.0f | % 6.2f |\n", i+1, ss, s->recd[i]/1024, utilisation(s->recd[i], s), s->sndd[i]/1024, utilisation(s->sndd[i], s)); } fprintf(hdl, "%s.-------------.--------.-------------.--------. \n\n", s2); } void make_gif(const char *path, struct stat *s, int sr) { gdImagePtr im; FILE *out; char ss[16]; int black, white, blue, red; //, green; int i, x, y, x1, y1, gx, gy, gl, gt, k, km; double v, mu, pu; time_t t; struct tm *tm; im = gdImageCreate(gif_x, gif_y); white = gdImageColorAllocate(im, 255,255,255); black = gdImageColorAllocate(im, 0, 0, 0); blue = gdImageColorAllocate(im, 0, 0,255); //green = gdImageColorAllocate(im, 0,255, 0); red = gdImageColorAllocate(im, 255, 0, 0); gx = gif_x - 80; gy = gif_y - 64; gl = 26; gt = 16; gdImageLine(im, gl + 0, gt + 0, gl + gx, gt + 0, black); gdImageLine(im, gl + gx, gt + 0, gl + gx, gt + gy, black); gdImageLine(im, gl + 0, gt + 0, gl + 0, gt + gy, black); gdImageLine(im, gl + 0, gt + gy, gl + gx, gt + gy, black); if(sr == 1) strcpy(ss, "Received"); else strcpy(ss, "Sent"); gdImageString(im, gdFontLarge, gif_x/2 - gdFontLarge->w * strlen(ss)/2, 0, ss, black); gx--; gy--; mu = 0; for(i = 0; i < s->use; i++) { if(sr == 1) v = s->recd[i]; else v = s->sndd[i]; if(mu < v) mu = v; } mu += mu/10; // Add 10% to the top, for a bit of a gap there if(mu > max_utilisation * factor(s)) mu = max_utilisation * factor(s); pu = mu * 100. / ((double)max_utilisation * factor(s)); if(pu == 0.0) pu = 0.0001; for(i = 0; i <= 5; i++) { gdImageLine(im, gl + 1, gt + i * gy / 5, gl + gx, gt + i * gy / 5, black); sprintf(ss, "%.0fK", ((5.-(double)i) * ((double)mu / 1024.) / 5.)); gdImageString(im, gdFontSmall, gl + gx + 2, gt + i * gy / 5 - gdFontSmall->h / 2, ss, black); sprintf(ss, "%.0f%%", (5.-(double)i) * (pu/5.)); gdImageString(im, gdFontSmall, gl - gdFontSmall->w * strlen(ss) - 2, gt + i * gy / 5 - gdFontSmall->h / 2, ss, black); } k = s->use; km = 1; while(k > 0 && gx / k < 12) { k /= 2; km *= 2; } for(i = 1; i < k; i++) { gdImageLine(im, gl + i * gx / k, gt + 1, gl + i * gx / k, gt + gy, black); t = (s->start + (i * km * s->step)); // current_time - (k-i) * km * s->step); tm = localtime(&t); switch(s->step) { case STEP_MONTH: sprintf(ss, "%d-%02d", tm->tm_mday, tm->tm_mon+1); break; case STEP_DAY: sprintf(ss, "%d-%02d", tm->tm_mday, tm->tm_mon+1); break; case STEP_HOUR: sprintf(ss, "%02d %d:%02d", tm->tm_mday, tm->tm_hour, tm->tm_min); break; case STEP_MINUTE: sprintf(ss, "%d:%02d", tm->tm_hour, tm->tm_min); break; } gdImageStringUp(im, gdFontSmall, gl + i * gx / k - gdFontSmall->h / 2, gt + gy + 2 + strlen(ss) * gdFontSmall->w, ss, black); //gdImageString(im, gdFontSmall, gl + i * gx / k - strlen(ss) * gdFontSmall->w/2, gt + gy + 2, ss, black); } x1 = 1; y1 = gy; k = s->use - 1; if(k == 0) { if(sr == 1) v = s->recd[0]; else v = s->sndd[0]; y = 1 + gy - ((double)v * (double)gy / (double)mu) - 1; gdImageLine(im, gl + 1, gt + y, gl + gx, gt + y, sr == 1 ? blue : red); } else for(i = 0; i < s->use; i++) { if(sr == 1) v = s->recd[i]; else v = s->sndd[i]; //printf("i: %d [sr:%d] v: %d mu: %d gy: %d (v*gy/mu): %d\n", i, sr, v, mu, gy, (v*gy/mu)); x = 1 + ((i+1) * gx / s->use); y = 1 + gy - ((double)v * (double)gy / (double)mu) - 1; gdImageLine(im, gl + x, gt + y, gl + x1, gt + y1, sr == 1 ? blue : red); x1 = x; y1 = y; } out = fopen(path, "wb"); gdImageGif(im, out); fclose(out); gdImageDestroy(im); } double factor(struct stat *s) { return (s->step == STEP_FOREVER ? current_time - s->start : s->step); }