Exemple #1
0
/**
 * \brief Periodically prints statistics about proccessing speed
 * 
 * @param config output manager's configuration
 * @return 0;
 */
static void *statistics_thread(void* config)
{
	struct output_manager_config *conf = (struct output_manager_config *) config;
	time_t begin = time(NULL), time_now, diff_time;

	uint64_t pkts, last_pkts, records, last_records, diff_pkts, diff_records;
	pkts = last_pkts = records = last_records = diff_pkts = diff_records = 0;

	uint64_t lost_records, last_lost_records, diff_lost_records;
	lost_records = last_lost_records = diff_lost_records = 0;
	
	/* create statistics config */
	conf->stats.total_cpu = 0;
	conf->stats.threads = NULL;
	conf->stats.cpus = sysconf(_SC_NPROCESSORS_ONLN);
	snprintf(conf->stats.tasks_dir, MAX_DIR_LEN, "/proc/%d/task/", getpid());

	// Create file handle in case statistics file has been specified in config
	FILE *stat_out_file = NULL;
	xmlNode *node = conf->plugins_config->collector_node;
	while (node != NULL) {
		// Skip processing this node in case it's a comment
		if (node->type == XML_COMMENT_NODE) {
			node = node->next;
			continue;
		}

		// Jump to collectingProcess tree, since 'statisticsFile' belongs to it (if present)
		if (xmlStrcmp(node->name, (const xmlChar *) "collectingProcess") == 0) {
			node = node->xmlChildrenNode;
		}

		if (xmlStrcmp(node->name, (const xmlChar *) "statisticsFile") == 0) {
			char *stat_out_file_path = (char *) xmlNodeGetContent(node->xmlChildrenNode);
			if (stat_out_file_path && strlen(stat_out_file_path) > 0) {
				/* Consists of the following elements:
				 *      strlen(stat_out_file_path) - length of supplied path
				 *      1 - dot (.)
				 *      5 - we assume that a PID has a maximum length of 5 digits
				 *      1 - null-terminating character
				 */
				int max_len = strlen(stat_out_file_path) + 1 + 5 + 1;
				char buf[max_len];

				// snprintf ensures null-termination if (max_len != 0), which is always true
				snprintf(buf, max_len, "%s.%d", stat_out_file_path, getpid());
				stat_out_file = fopen(buf, "w");
			} else {
				MSG_ERROR(msg_module, "Configuration error: 'statisticsFile' node has no value");
			}

			xmlFree(stat_out_file_path);

			// No need to continue tree traversal, because 'statisticsFile' is only node to look for
			break;
		}

		node = node->next;
	}
	
	/* Catch SIGUSR1 */
	signal(SIGUSR1, sig_handler);
	
	/* set thread name */
	prctl(PR_SET_NAME, "ipfixcol:stats", 0, 0, 0);
	
	while (conf->stat_interval) {
		sleep(conf->stat_interval);
		
		/* killed by output manager*/
		if (conf->stats.done) {
			break;
		}
		
		/* Compute time */
		time_now = time(NULL);
		diff_time = time_now - begin;
		
		/* Update and save packets counter */
		pkts = conf->packets;
		diff_pkts = pkts - last_pkts;
		last_pkts = pkts;
		
		/* Update and save data records counter */
		records = conf->data_records;
		diff_records = records - last_records;
		last_records = records;

		/* Collect lost data record counts from Data Managers */
		lost_records = conf->lost_data_records;
		diff_lost_records = lost_records - last_lost_records;
		last_lost_records = lost_records;

		/* print info */
		MSG_INFO(stat_module, "Time: %lu", time_now);
		MSG_INFO(stat_module, "%15s %15s %15s %15s %15s %15s %20s", "total time", "total packets", "tot. data rec.", "lost data rec.", "packets/s", "data records/s", "lost data records/s");
		MSG_INFO(stat_module, "%15lu %15lu %15lu %15lu %15lu %15lu %20lu", diff_time, pkts, records, lost_records, diff_pkts/conf->stat_interval, diff_records/conf->stat_interval, diff_lost_records/conf->stat_interval);

		if (stat_out_file) {
			rewind(stat_out_file); // Move to beginning of file
			fprintf(stat_out_file, "%s=%lu\n", "TIME", time_now);
			fprintf(stat_out_file, "%s=%lu\n", "RUN_TIME", diff_time);
			fprintf(stat_out_file, "%s=%lu\n", "PACKETS", pkts);
			fprintf(stat_out_file, "%s=%lu\n", "DATA_REC", records);
			fprintf(stat_out_file, "%s=%lu\n", "LOST_DATA_REC", lost_records);
			fprintf(stat_out_file, "%s=%lu\n", "PACKETS_SEC", diff_pkts/conf->stat_interval);
			fprintf(stat_out_file, "%s=%lu\n", "DATA_REC_SEC", diff_records/conf->stat_interval);
			fprintf(stat_out_file, "%s=%lu\n", "LOST_DATA_REC_SEC", diff_lost_records/conf->stat_interval);
			fflush(stat_out_file);
		}
		
		/* print cpu usage by threads */
		statistics_print_cpu(&(conf->stats), stat_out_file);
		
		/* print buffers usage */
		statistics_print_buffers(conf, stat_out_file);

		MSG_INFO(stat_module, "");
	}

	if (stat_out_file) {
		fclose(stat_out_file);
	}
	
	return NULL;
}
Exemple #2
0
/**
 * \brief Periodically prints statistics about proccessing speed
 *
 * @param config Output Manager configuration
 * @return 0;
 */
static void *statistics_thread(void* config)
{
	struct output_manager_config *conf = (struct output_manager_config *) config;
	time_t begin = time(NULL), time_now, run_time;

	/* Create statistics config */
	conf->stats.total_cpu = 0;
	conf->stats.threads = NULL;
	conf->stats.cpus = sysconf(_SC_NPROCESSORS_ONLN);
	snprintf(conf->stats.tasks_dir, MAX_DIR_LEN, "/proc/%d/task/", getpid());

	/* If statistics are enabled (using -S), printing them to console is default */
	uint8_t print_stat_to_file = 0;
	uint8_t print_stat_to_console = 1;

	/* Process XML config */
	char *full_stat_out_file_path = NULL;
	xmlNode *node = conf->plugins_config->collector_node;
	while (node != NULL) {
		/* Skip processing this node in case it's a comment */
		if (node->type == XML_COMMENT_NODE) {
			node = node->next;
			continue;
		}

		/* Jump to collectingProcess tree, since 'statisticsFile' belongs to it (if present) */
		if (xmlStrcmp(node->name, (const xmlChar *) "collectingProcess") == 0) {
			node = node->xmlChildrenNode;
		}

		if (xmlStrcmp(node->name, (const xmlChar *) "statisticsFile") == 0) {
			/* Disable printing statistics to console when printing to file */
			print_stat_to_console = 0;

			char *stat_out_file_path = (char *) xmlNodeGetContent(node->xmlChildrenNode);
			if (stat_out_file_path && strlen(stat_out_file_path) > 0) {
				print_stat_to_file = 1;

				/* Determine statistics file path, i.e., full path minus basename */
				char stat_out_path[strlen(stat_out_file_path) + 1];
				strncpy_safe(stat_out_path, stat_out_file_path, strlen(stat_out_file_path) - strlen(basename(stat_out_file_path)));

				/* Check whether statistics file path exists */
				DIR *stat_out_dir;
				if ((stat_out_dir = opendir(stat_out_path)) == NULL) {
					MSG_ERROR(msg_module, "Statistics file directory '%s' does not exist", stat_out_path);
					xmlFree(stat_out_file_path);

					/* Skip to next XML node in configuration */
					node = node->next;
					continue;
				} else {
					closedir(stat_out_dir);
				}

				/* Clean up previous statistics files */
				char glob_path[strlen(stat_out_file_path) + 2]; // +2 is for wildcard (*) and null-terminating char
				strncpy_safe(glob_path, stat_out_file_path, strlen(stat_out_file_path) + 1);
				glob_path[strlen(stat_out_file_path)] = '*';
				glob_path[strlen(stat_out_file_path) + 1] = '\0';

				/* Search for files using glob */
				int glob_ret, glob_flags = 0;
				glob_t glob_results;
				if ((glob_ret = glob(glob_path, glob_flags, NULL, &glob_results)) == 0) {
					uint16_t i, stat_files_deleted = 0;
					for (i = 0; i < glob_results.gl_pathc; ++i) {
						if ((remove(glob_results.gl_pathv[i])) == 0) {
							++stat_files_deleted;
						} else {
							MSG_ERROR(msg_module, "An error occurred while deleting statistics file '%s'", glob_results.gl_pathv[i]);
						}
					}

					MSG_INFO(msg_module, "Cleaned up %u old statistics file(s)", stat_files_deleted);
					globfree(&glob_results);
				} else if (glob_ret == GLOB_NOMATCH) {
					/* No matching files/directories found; do nothing */
				} else {
					/* Another glob error occurred; do nothing */
				}

				/* Consists of the following elements:
				 *      strlen(stat_out_file_path) - length of supplied path
				 *      1 - dot (.)
				 *      5 - we assume that a PID has a maximum length of 5 digits
				 *      1 - null-terminating character
				 */
				uint8_t max_len = strlen(stat_out_file_path) + 1 + 5 + 1;
				full_stat_out_file_path = calloc(max_len, sizeof(char));

				/* snprintf ensures null-termination if (max_len != 0), which is always true */
				snprintf(full_stat_out_file_path, max_len, "%s.%d", stat_out_file_path, getpid());
			} else {
				MSG_ERROR(msg_module, "Configuration error: 'statisticsFile' node has no value");
			}

			xmlFree(stat_out_file_path);

			/* No need to continue tree traversal, because 'statisticsFile' is only node to look for */
			break;
		}

		node = node->next;
	}

	/* Set thread name */
	prctl(PR_SET_NAME, "ipfixcol:stats", 0, 0, 0);

	FILE *stat_out_file = NULL;
	while (conf->stat_interval && !conf->stats.done) { /* stats.done can be set by Output Manager */
		/* Sleep */
		struct timespec tv;
		tv.tv_sec = conf->stat_interval;
		tv.tv_nsec = 0;

		/* Reconfiguration (SIGUSR1) cause sleep interruption */
		while (nanosleep(&tv, &tv) == -1 && errno == EINTR && !conf->stats.done);

		/* Compute time */
		time_now = time(NULL);
		run_time = time_now - begin;

		/* Print info */
		if (print_stat_to_file) {
			if (full_stat_out_file_path) {
				stat_out_file = fopen(full_stat_out_file_path, "w");

				if (!stat_out_file) {
					MSG_ERROR(msg_module, "Could not open statistics file '%s'; stopping statistics thread", full_stat_out_file_path);
					break;
				}

				fprintf(stat_out_file, "%s=%lu\n", "TIME", time_now);
				fprintf(stat_out_file, "%s=%lu\n", "RUN_TIME", run_time);
			} else {
				MSG_ERROR(msg_module, "Could not determine statistics file path; stopping statistics thread");
				break;
			}
		} else if (print_stat_to_console) {
			MSG_ALWAYS("Statistics", NULL);
			MSG_ALWAYS(" | Time: %lu, run time: %lu", time_now, run_time);
			MSG_ALWAYS(" | %10s %15s %15s %15s %15s %15s %20s", "ODID", "packets", "data rec.", "lost data rec.", "packets/s", "data records/s", "lost data records/s");
		}

		/* Variables for calculating sums */
		uint64_t packets_total = 0;
		uint64_t data_records_total = 0;
		uint64_t lost_data_records_total = 0;

		/* Variables for calculating delta (to previous measurement) */
		uint32_t delta_packets;
		uint32_t delta_data_records;
		uint32_t delta_lost_data_records;

		struct input_info_node *aux_node = input_info_list;
		uint8_t aux_node_count = 0;
		while (aux_node) {
			delta_packets = aux_node->input_info->packets - aux_node->last_packets;
			delta_data_records = aux_node->input_info->data_records - aux_node->last_data_records;
			delta_lost_data_records = aux_node->input_info->sequence_number - aux_node->input_info->data_records - aux_node->last_lost_data_records;

			if (print_stat_to_file) {
				fprintf(stat_out_file, "%s_%u=%" PRIu64 "\n", "PACKETS",
						aux_node->input_info->odid, aux_node->input_info->packets);
				fprintf(stat_out_file, "%s_%u=%" PRIu64 "\n", "DATA_REC",
						aux_node->input_info->odid, aux_node->input_info->data_records);
				fprintf(stat_out_file, "%s_%u=%" PRIu64 "\n", "LOST_DATA_REC",
						aux_node->input_info->odid, aux_node->input_info->sequence_number - aux_node->input_info->data_records);
				fprintf(stat_out_file, "%s_%u=%u\n", "PACKETS_SEC",
						aux_node->input_info->odid, delta_packets / conf->stat_interval);
				fprintf(stat_out_file, "%s_%u=%u\n", "DATA_REC_SEC",
						aux_node->input_info->odid, delta_data_records / conf->stat_interval);
				fprintf(stat_out_file, "%s_%u=%u\n", "LOST_DATA_REC_SEC",
						aux_node->input_info->odid, delta_lost_data_records / conf->stat_interval);
			} else if (print_stat_to_console) {
				MSG_ALWAYS(" | %10u %15lu %15lu %15lu %15u %15u %20u",
						aux_node->input_info->odid,
						aux_node->input_info->packets,
						aux_node->input_info->data_records,
						aux_node->input_info->sequence_number - aux_node->input_info->data_records,
						delta_packets / conf->stat_interval,
						delta_data_records / conf->stat_interval,
						delta_lost_data_records / conf->stat_interval);
			}

			/* Add values per ODID to sum */
			packets_total += aux_node->input_info->packets;
			data_records_total += aux_node->input_info->data_records;
			lost_data_records_total += aux_node->input_info->sequence_number - aux_node->input_info->data_records;

			/* Update 'last' values */
			aux_node->last_packets = aux_node->input_info->packets;
			aux_node->last_data_records = aux_node->input_info->data_records;
			aux_node->last_lost_data_records = aux_node->input_info->sequence_number - aux_node->input_info->data_records;

			aux_node = aux_node->next;
			++aux_node_count;
		}

		if (print_stat_to_console && aux_node_count > 1) {
			/* Print totals row, but only in case there is more than one ODID */
			MSG_ALWAYS(" | %s", "----------------------------------------------------------");
			MSG_ALWAYS(" | %10s %15lu %15lu %15lu", "Total:", packets_total, data_records_total, lost_data_records_total);
		}

		/* Print CPU usage by threads */
		statistics_print_cpu(&(conf->stats), stat_out_file);

		/* Print buffer usage */
		statistics_print_buffers(conf, stat_out_file);

		/* Flush input stream and close file */
		if (print_stat_to_file) {
			fflush(stat_out_file);
			fclose(stat_out_file);
		}
	}

	if (print_stat_to_file) {
		free(full_stat_out_file_path);
	}

	return NULL;
}