diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 4 | ||||
| -rw-r--r-- | src/loggingrb.c | 98 | ||||
| -rw-r--r-- | src/strrb.c | 170 | ||||
| -rw-r--r-- | src/vty/logging_vty.c | 85 | 
4 files changed, 351 insertions, 6 deletions
| diff --git a/src/Makefile.am b/src/Makefile.am index b425ea19..081be966 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,8 +11,8 @@ libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c bits.c \  			 write_queue.c utils.c socket.c \  			 logging.c logging_syslog.c rate_ctr.c \  			 gsmtap_util.c crc16.c panic.c backtrace.c \ -			 conv.c application.c rbtree.c \ -			 crc8gen.c crc16gen.c crc32gen.c crc64gen.c +			 conv.c application.c rbtree.c strrb.c \ +			 loggingrb.c crc8gen.c crc16gen.c crc32gen.c crc64gen.c  BUILT_SOURCES = crc8gen.c crc16gen.c crc32gen.c crc64gen.c diff --git a/src/loggingrb.c b/src/loggingrb.c new file mode 100644 index 00000000..8faa5b11 --- /dev/null +++ b/src/loggingrb.c @@ -0,0 +1,98 @@ +/* Ringbuffer-backed logging support code */ + +/* (C) 2012-2013 by Katerina Barone-Adesi + * All Rights Reserved + * + * 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 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/*! \addtogroup logging + *  @{ + */ + +/*! \file loggingrb.c */ + +#include <osmocom/core/strrb.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/loggingrb.h> + +static void _rb_output(struct log_target *target, +			  unsigned int level, const char *log) +{ +	osmo_strrb_add(target->tgt_rb.rb, log); +} + +/*! \brief Return the number of log strings in the osmo_strrb-backed target. + *  \param[in] target The target to search. + * + *  \return The number of log strings in the osmo_strrb-backed target. + */ +size_t log_target_rb_used_size(struct log_target const *target) +{ +	return osmo_strrb_elements(target->tgt_rb.rb); +} + +/*! \brief Return the capacity of the osmo_strrb-backed target. + *  \param[in] target The target to search. + * + * Note that this is the capacity (aka max number of messages). + * It is not the number of unused message slots. + *  \return The number of log strings in the osmo_strrb-backed target. + */ +size_t log_target_rb_avail_size(struct log_target const *target) +{ +	struct osmo_strrb *rb = target->tgt_rb.rb; +	return rb->size - 1; +} + +/*! \brief Return the nth log entry in a target. + *  \param[in] target The target to search. + *  \param[in] logindex The index of the log entry/error message. + * + *  \return A pointer to the nth message, or NULL if logindex is invalid. + */ +const char *log_target_rb_get(struct log_target const *target, size_t logindex) +{ +	return osmo_strrb_get_nth(target->tgt_rb.rb, logindex); +} + +/*! \brief Create a new logging target for ringbuffer-backed logging. + *  \param[in] size The size of the internal backing osmo_strrb (messages). + *  \returns A log target in case of success, NULL in case of error. + */ +struct log_target *log_target_create_rb(size_t size) +{ +	struct log_target *target; +	struct osmo_strrb *rb; + +	target = log_target_create(); +	if (!target) +		return NULL; + +	rb = osmo_strrb_create(target, size + 1); +	if (!rb) { +		log_target_destroy(target); +		return NULL; +	} + +	target->tgt_rb.rb = rb; +	target->type = LOG_TGT_TYPE_STRRB; +	target->output = _rb_output; + +	return target; +} + +/* @} */ diff --git a/src/strrb.c b/src/strrb.c new file mode 100644 index 00000000..626ade69 --- /dev/null +++ b/src/strrb.c @@ -0,0 +1,170 @@ +/* Ringbuffer implementation, tailored for logging. + * This is a lossy ringbuffer. It keeps up to N of the newest messages, + * overwriting the oldest as newer ones come in. + * + * (C) 2012-2013, Katerina Barone-Adesi <kat.obsc@gmail.com> + * All Rights Reserved + * + * 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 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/*! \file strrb.c + *  \brief Lossy string ringbuffer for logging; keeps newest messages. + */ + +#include <stdio.h> +#include <string.h> +#include <strings.h> + +#include <osmocom/core/strrb.h> + +/* Ringbuffer assumptions, invarients, and notes: + * - start is the index of the first used index slot in the ring buffer. + * - end is the index of the next index slot in the ring buffer. + * - start == end => buffer is empty + * - Consequence: the buffer can hold at most size - 1 messages + * (if this were not the case, full and empty buffers would be indistinguishable + * given the conventions in this implementation). + * - Whenever the ringbuffer is full, start is advanced. The second oldest + * message becomes unreachable by valid indexes (end is not a valid index) + * and the oldest message is overwritten (if there was a message there, which + * is the case unless this is the first time the ringbuffer becomes full). +*/ + +/*! \brief Create an empty, initialized osmo_strrb. + *  \param[in] ctx The talloc memory context which should own this. + *  \param[in] rb_size The number of messages the osmo_strrb can hold. + *  \returns A struct osmo_strrb* on success, NULL in case of error. + * + * This function creates and initializes a ringbuffer. + */ + +struct osmo_strrb *osmo_strrb_create(TALLOC_CTX * ctx, size_t rb_size) +{ +	struct osmo_strrb *rb = NULL; +	unsigned int i; + +	rb = talloc_zero(ctx, struct osmo_strrb); +	if (!rb) +		goto alloc_error; + +	/* start and end are zero already, which is correct */ +	rb->size = rb_size; + +	rb->buffer = talloc_array(rb, char *, rb->size); +	if (!rb->buffer) +		goto alloc_error; +	for (i = 0; i < rb->size; i++) { +		rb->buffer[i] = +		    talloc_zero_size(rb->buffer, RB_MAX_MESSAGE_SIZE); +		if (!rb->buffer[i]) +			goto alloc_error; +	} + +	return rb; + +alloc_error:			/* talloc_free(NULL) is safe */ +	talloc_free(rb); +	return NULL; +} + +/*! \brief Check if an osmo_strrb is empty. + *  \param[in] rb The osmo_strrb to check. + *  \returns True if the osmo_strrb is empty, false otherwise. + */ +bool osmo_strrb_is_empty(const struct osmo_strrb *rb) +{ +	return rb->end == rb->start; +} + +/*! \brief Return a pointer to the Nth string in the osmo_strrb. + * \param[in] rb The osmo_strrb to search. + * \param[in] string_index The index sought (N), zero-indexed. + * + * Return a pointer to the Nth string in the osmo_strrb. + * Return NULL if there is no Nth string. + * Note that N is zero-indexed. + * \returns A pointer to the target string on success, NULL in case of error. + */ +const char *osmo_strrb_get_nth(const struct osmo_strrb *rb, +			       unsigned int string_index) +{ +	unsigned int offset = string_index + rb->start; + +	if ((offset >= rb->size) && (rb->start > rb->end)) +		offset -= rb->size; +	if (_osmo_strrb_is_bufindex_valid(rb, offset)) +		return rb->buffer[offset]; + +	return NULL; +} + +bool _osmo_strrb_is_bufindex_valid(const struct osmo_strrb *rb, +				   unsigned int bufi) +{ +	if (osmo_strrb_is_empty(rb)) +		return 0; +	if ((bufi >= rb->size) || (bufi < 0)) +		return 0; +	if (rb->start < rb->end) +		return (bufi >= rb->start) && (bufi < rb->end); +	return (bufi < rb->end) || (bufi >= rb->start); +} + +/*! \brief Count the number of log messages in an osmo_strrb. + *  \param[in] rb The osmo_strrb to count the elements of. + * + *  \returns The number of log messages in the osmo_strrb. + */ +size_t osmo_strrb_elements(const struct osmo_strrb *rb) +{ +	if (rb->end < rb->start) +		return rb->end + (rb->size - rb->start); + +	return rb->end - rb->start; +} + +/*! \brief Add a string to the osmo_strrb. + * \param[in] rb The osmo_strrb to add to. + * \param[in] data The string to add. + * + * Add a message to the osmo_strrb. + * Older messages will be overwritten as necessary. + * \returns 0 normally, 1 as a warning (ie, if data was truncated). + */ +int osmo_strrb_add(struct osmo_strrb *rb, const char *data) +{ +	size_t len = strlen(data); +	int ret = 0; + +	if (len >= RB_MAX_MESSAGE_SIZE) { +		len = RB_MAX_MESSAGE_SIZE - 1; +		ret = 1; +	} + +	memcpy(rb->buffer[rb->end], data, len); +	rb->buffer[rb->end][len] = '\0'; + +	rb->end += 1; +	rb->end %= rb->size; + +	/* The buffer is full; oldest message is forgotten - see notes above */ +	if (rb->end == rb->start) { +		rb->start += 1; +		rb->start %= rb->size; +	} +	return ret; +} diff --git a/src/vty/logging_vty.c b/src/vty/logging_vty.c index d473f129..ace346a2 100644 --- a/src/vty/logging_vty.c +++ b/src/vty/logging_vty.c @@ -27,8 +27,8 @@  #include <osmocom/core/talloc.h>  #include <osmocom/core/logging.h>  #include <osmocom/core/utils.h> - -//#include <openbsc/vty.h> +#include <osmocom/core/strrb.h> +#include <osmocom/core/loggingrb.h>  #include <osmocom/vty/command.h>  #include <osmocom/vty/buffer.h> @@ -252,8 +252,8 @@ static void vty_print_logtarget(struct vty *vty, const struct log_info *info,  #define SHOW_LOG_STR "Show current logging configuration\n"  DEFUN(show_logging_vty, -      show_logging_vty_cmd, -      "show logging vty", +	show_logging_vty_cmd, +	"show logging vty",  	SHOW_STR SHOW_LOG_STR  	"Show current logging configuration for this vty\n")  { @@ -267,6 +267,33 @@ DEFUN(show_logging_vty,  	return CMD_SUCCESS;  } +DEFUN(show_alarms, +	show_alarms_cmd, +	"show alarms", +	SHOW_STR SHOW_LOG_STR +	"Show the contents of the logging ringbuffer\n") +{ +	int i, num_alarms; +	struct osmo_strrb *rb; +	struct log_target *tgt = log_target_find(LOG_TGT_TYPE_STRRB, NULL); +	if (!tgt) { +		vty_out(vty, "%% No alarms, run 'log alarms <2-32700>'%s", +			VTY_NEWLINE); +		return CMD_WARNING; +	} + +	rb = tgt->tgt_rb.rb; +	num_alarms = osmo_strrb_elements(rb); + +	vty_out(vty, "%% Showing %i alarms%s", num_alarms, VTY_NEWLINE); + +	for (i = 0; i < num_alarms; i++) +		vty_out(vty, "%% %s%s", osmo_strrb_get_nth(rb, i), +			VTY_NEWLINE); + +	return CMD_SUCCESS; +} +  gDEFUN(cfg_description, cfg_description_cmd,  	"description .TEXT",  	"Save human-readable decription of the object\n" @@ -510,6 +537,49 @@ DEFUN(cfg_no_log_file, cfg_no_log_file_cmd,  	return CMD_SUCCESS;  } +DEFUN(cfg_log_alarms, cfg_log_alarms_cmd, +	"log alarms <2-32700>", +	LOG_STR "Logging alarms to osmo_strrb\n" +	"Maximum number of messages to log\n") +{ +	struct log_target *tgt; +	unsigned int rbsize = atoi(argv[0]); + +	tgt = log_target_find(LOG_TGT_TYPE_STRRB, NULL); +	if (tgt) +		log_target_destroy(tgt); + +	tgt = log_target_create_rb(rbsize); +	if (!tgt) { +		vty_out(vty, "%% Unable to create osmo_strrb (size %u)%s", +			rbsize, VTY_NEWLINE); +		return CMD_WARNING; +	} +	log_add_target(tgt); + +	vty->index = tgt; +	vty->node = CFG_LOG_NODE; + +	return CMD_SUCCESS; +} + +DEFUN(cfg_no_log_alarms, cfg_no_log_alarms_cmd, +	"no log alarms", +	NO_STR LOG_STR "Logging alarms to osmo_strrb\n") +{ +	struct log_target *tgt; + +	tgt = log_target_find(LOG_TGT_TYPE_STRRB, NULL); +	if (!tgt) { +		vty_out(vty, "%% No osmo_strrb target found%s", VTY_NEWLINE); +		return CMD_WARNING; +	} + +	log_target_destroy(tgt); + +	return CMD_SUCCESS; +} +  static int config_write_log_single(struct vty *vty, struct log_target *tgt)  {  	int i; @@ -533,6 +603,10 @@ static int config_write_log_single(struct vty *vty, struct log_target *tgt)  	case LOG_TGT_TYPE_FILE:  		vty_out(vty, "log file %s%s", tgt->tgt_file.fname, VTY_NEWLINE);  		break; +	case LOG_TGT_TYPE_STRRB: +		vty_out(vty, "log alarms %zu%s", +			log_target_rb_avail_size(tgt), VTY_NEWLINE); +		break;  	}  	vty_out(vty, "  logging filter all %u%s", @@ -590,6 +664,7 @@ void logging_vty_add_cmds(const struct log_info *cat)  	logging_level_cmd.doc = log_vty_command_description(cat);  	install_element_ve(&logging_level_cmd);  	install_element_ve(&show_logging_vty_cmd); +	install_element_ve(&show_alarms_cmd);  	install_node(&cfg_log_node, config_write_log);  	install_default(CFG_LOG_NODE); @@ -603,6 +678,8 @@ void logging_vty_add_cmds(const struct log_info *cat)  	install_element(CONFIG_NODE, &cfg_no_log_stderr_cmd);  	install_element(CONFIG_NODE, &cfg_log_file_cmd);  	install_element(CONFIG_NODE, &cfg_no_log_file_cmd); +	install_element(CONFIG_NODE, &cfg_log_alarms_cmd); +	install_element(CONFIG_NODE, &cfg_no_log_alarms_cmd);  #ifdef HAVE_SYSLOG_H  	install_element(CONFIG_NODE, &cfg_log_syslog_cmd);  	install_element(CONFIG_NODE, &cfg_log_syslog_local_cmd); | 
