Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable log filtering #2844

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Prev Previous commit
lib: Enable log filtering
Enable the users to decide for what kinds of log messages their log
callbacks will be called. This filtering happens in the library in
order to avoid the malloc call in log__printf (logging_mosq.c) for
messages that would be ignored anyway.
By default, no messages are filtered out. The set of allowed log types
can be configured by mosquitto_log_levels_set.

Note: Two additional log level masks (WARNING_AND_ABOVE and
      NOTICE_AND_ABOVE) have been added as shortcuts for
      convenience.

Signed-off-by: Andrzej Turko <[email protected]>
  • Loading branch information
a-turko committed Jul 6, 2023
commit 41357095996d80faa60a8b43c27c3266f06e4e7f
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ test/unit/broker/bridge_topic_test
test/unit/coverage.info
test/unit/broker/keepalive_test
test/unit/lib/lib_test
test/unit/lib/logs_test
test/unit/broker/persist_read_test
test/unit/broker/persist_write_test
test/unit/broker/subs_test
Expand Down
28 changes: 28 additions & 0 deletions include/mosquitto.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ extern "C" {
#define MOSQ_LOG_WEBSOCKETS (1<<7)
#define MOSQ_LOG_INTERNAL 0x80000000U
#define MOSQ_LOG_ALL 0xFFFFFFFFU
#define MOSQ_LOG_WARNING_AND_ABOVE (MOSQ_LOG_WARNING | MOSQ_LOG_ERR)
#define MOSQ_LOG_NOTICE_AND_ABOVE (MOSQ_LOG_WARNING_AND_ABOVE | MOSQ_LOG_NOTICE)


/* Enum: mosq_err_t
* Integer values returned from many libmosquitto functions. */
Expand Down Expand Up @@ -2362,6 +2365,31 @@ libmosq_EXPORT void mosquitto_unsubscribe2_v5_callback_set(struct mosquitto *mos
*/
libmosq_EXPORT void mosquitto_log_callback_set(struct mosquitto *mosq, void (*on_log)(struct mosquitto *, void *, int, const char *));

/*
* Function: mosquitto_log_levels_set
*
* Set the logging level. This should be used to configure filtering for
* event logging information from the client library. If this function
* is not called, all logs are passed to the log callback by default
* (provided that the callback has been set).
*
* mosq - a valid mosquitto instance.
* log_types - a mask of the levels of logs for which the log callback is
* to be called. Any combination of log types is valid, for example:
* MOSQ_LOG_NONE
* MOSQ_LOG_NOTICE_AND_ABOVE
* MOSQ_LOG_WARNING_AND_ABOVE
* MOSQ_LOG_ERR
* MOSQ_LOG_DEBUG
* MOSQ_LOG_SUBSCRIBE
* MOSQ_LOG_UNSUBSCRIBE
* MOSQ_LOG_WEBSOCKETS
* MOSQ_LOG_INTERNAL
* MOSQ_LOG_ALL
*/
libmosq_EXPORT void mosquitto_log_levels_set(struct mosquitto *mosq, unsigned int log_levels);



/* =============================================================================
*
Expand Down
6 changes: 6 additions & 0 deletions lib/callbacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ void mosquitto_log_callback_set(struct mosquitto *mosq, void (*on_log)(struct mo
pthread_mutex_unlock(&mosq->log_callback_mutex);
}

void mosquitto_log_levels_set(struct mosquitto *mosq, unsigned int log_levels)
{
pthread_mutex_lock(&mosq->log_callback_mutex);
mosq->log_levels = log_levels;
pthread_mutex_unlock(&mosq->log_callback_mutex);
}

void callback__on_pre_connect(struct mosquitto *mosq)
{
Expand Down
2 changes: 1 addition & 1 deletion lib/logging_mosq.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ int log__printf(struct mosquitto *mosq, unsigned int priority, const char *fmt,
assert(fmt);

pthread_mutex_lock(&mosq->log_callback_mutex);
if(mosq->on_log){
if(mosq->on_log && (mosq->log_levels & priority)){
len = strlen(fmt) + 500;
s = mosquitto__malloc(len*sizeof(char));
if(!s){
Expand Down
1 change: 1 addition & 0 deletions lib/mosquitto.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_st
mosq->on_subscribe = NULL;
mosq->on_unsubscribe = NULL;
mosq->on_log = NULL;
mosq->log_levels = MOSQ_LOG_ALL;
mosq->host = NULL;
mosq->port = 1883;
mosq->reconnect_delay = 1;
Expand Down
1 change: 1 addition & 0 deletions lib/mosquitto_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ struct mosquitto {
void (*on_unsubscribe2_v5)(struct mosquitto *, void *userdata, int mid, int reason_code_count, const int *reason_codes, const mosquitto_property *props);
void (*on_log)(struct mosquitto *, void *userdata, int level, const char *str);
/*void (*on_error)();*/
unsigned int log_levels;
char *host;
char *bind_address;
unsigned int reconnects;
Expand Down
25 changes: 24 additions & 1 deletion test/unit/lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ LIB_OBJS = \
${R}/lib/util_topic.o \
${R}/lib/utf8_mosq.o

LOGS_TEST_OBJS = \
logs_test.o \
logs_stubs.o

LOGS_LIB_OBJS = \
${R}/lib/callbacks.o \
${R}/lib/logging_mosq.o \
${R}/lib/memory_mosq.o \
${R}/lib/mosquitto.o \
${R}/lib/utf8_mosq.o

all : test-compile

Expand All @@ -46,15 +56,27 @@ check : test
lib_test : ${TEST_OBJS} ${LIB_OBJS}
$(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^ $(LDADD)

logs_test : ${LOGS_TEST_OBJS} ${LOGS_LIB_OBJS}
$(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^ $(LDADD)

${TEST_OBJS} : %.o: %.c
${CROSS_COMPILE}${CC} $(CPPFLAGS) $(CFLAGS) -c $< -o $@

lib_stubs.o : stubs.c
${CROSS_COMPILE}$(CC) $(LIB_CPPFLAGS) $(LIB_CFLAGS) $(CFLAGS) $(CPPFLAGS) -c $< -o $@

${R}/lib/callbacks.o : ${R}/lib/callbacks.c
$(MAKE) -C ${R}/lib/ callbacks.o

${R}/lib/logging_mosq.o : ${R}/lib/logging_mosq.c
$(MAKE) -C ${R}/lib/ logging_mosq.o

${R}/lib/misc_mosq.o : ${R}/common/misc_mosq.c
$(MAKE) -C ${R}/lib/ misc_mosq.o

${R}/lib/mosquitto.o : ${R}/lib/mosquitto.c
$(MAKE) -C ${R}/lib/ mosquitto.o

${R}/lib/packet_datatypes.o : ${R}/lib/packet_datatypes.c
$(MAKE) -C ${R}/lib/ packet_datatypes.o

Expand All @@ -73,10 +95,11 @@ ${R}/lib/util_topic.o : ${R}/lib/util_topic.c
${R}/lib/utf8_mosq.o : ${R}/lib/utf8_mosq.c
$(MAKE) -C ${R}/lib/ utf8_mosq.o

build : lib_test
build : lib_test logs_test

test : build
./lib_test
./logs_test

test-compile: build

Expand Down
73 changes: 73 additions & 0 deletions test/unit/lib/logs_stubs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "config.h"
#include "mosquitto.h"
#include "mosquitto_internal.h"

#include <time.h>

time_t mosquitto_time(void)
{
return 123;
}

int net__socket_close(struct mosquitto *mosq)
{
UNUSED(mosq);

return MOSQ_ERR_SUCCESS;
}

int net__socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW)
{
UNUSED(pairR);
UNUSED(pairW);
return MOSQ_ERR_ERRNO;
}

int net__init(void)
{
return MOSQ_ERR_SUCCESS;
}

bool net__is_connected(struct mosquitto *mosq)
{
UNUSED(mosq);
return false;
}

void net__cleanup(void) {}

void message__cleanup(struct mosquitto_message_all **message)
{
UNUSED(message);
}

void message__cleanup_all(struct mosquitto *mosq)
{
UNUSED(mosq);
}

void packet__cleanup(struct mosquitto__packet *packet)
{
UNUSED(packet);
}

void packet__cleanup_all(struct mosquitto *mosq)
{
UNUSED(mosq);
}

void packet__cleanup_all_no_locks(struct mosquitto *mosq)
{
UNUSED(mosq);
}

int will__clear(struct mosquitto *mosq)
{
UNUSED(mosq);
return MOSQ_ERR_SUCCESS;
}

void mosquitto_property_free_all(mosquitto_property **property)
{
UNUSED(property);
}
99 changes: 99 additions & 0 deletions test/unit/lib/logs_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/* Tests of log filtering */

#include <CUnit/CUnit.h>
#include <CUnit/Basic.h>

#include <util_mosq.h>
#include <logging_mosq.h>

unsigned int last_log_level;

static void on_log(struct mosquitto *mosq, void *obj, int level, const char *str)
{
last_log_level = (unsigned int)level;
UNUSED(mosq);
UNUSED(obj);
UNUSED(str);
}

static bool log_on_level(struct mosquitto *mosq, unsigned int level)
{
last_log_level = MOSQ_LOG_ALL;
log__printf(mosq, level, "msg");
return last_log_level == level;
}

static void TEST_logs(void)
{
struct mosquitto *mosq;

mosquitto_lib_init();
mosq = mosquitto_new("log check", true, NULL);
CU_ASSERT(mosq != NULL);
mosquitto_log_callback_set(mosq, on_log);

/* default (log all) */
CU_ASSERT(log_on_level(mosq, MOSQ_LOG_INFO));
CU_ASSERT(log_on_level(mosq, MOSQ_LOG_ERR));
CU_ASSERT(log_on_level(mosq, MOSQ_LOG_SUBSCRIBE));

/* warning and above */
mosquitto_log_levels_set(mosq, MOSQ_LOG_WARNING_AND_ABOVE);
CU_ASSERT(!log_on_level(mosq, MOSQ_LOG_INFO));
CU_ASSERT(log_on_level(mosq, MOSQ_LOG_WARNING));
CU_ASSERT(!log_on_level(mosq, MOSQ_LOG_DEBUG));
CU_ASSERT(log_on_level(mosq, MOSQ_LOG_ERR));
CU_ASSERT(!log_on_level(mosq, MOSQ_LOG_SUBSCRIBE));

/* errors and subscribe */
mosquitto_log_levels_set(mosq, MOSQ_LOG_ERR | MOSQ_LOG_SUBSCRIBE);
CU_ASSERT(!log_on_level(mosq, MOSQ_LOG_DEBUG));
CU_ASSERT(!log_on_level(mosq, MOSQ_LOG_WARNING));
CU_ASSERT(log_on_level(mosq, MOSQ_LOG_ERR));
CU_ASSERT(log_on_level(mosq, MOSQ_LOG_SUBSCRIBE));

mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
}

/* ========================================================================
* TEST SUITE SETUP
* ======================================================================== */


int main(int argc, char *argv[])
{
CU_pSuite test_suite = NULL;
unsigned int fails;

UNUSED(argc);
UNUSED(argv);

if(CU_initialize_registry() != CUE_SUCCESS){
printf("Error initializing CUnit registry.\n");
return 1;
}

test_suite = CU_add_suite("Logs", NULL, NULL);
if(!test_suite){
printf("Error adding CUnit Logs test suite.\n");
CU_cleanup_registry();
return 1;
}

if(0
|| !CU_add_test(test_suite, "Logs", TEST_logs)
){

printf("Error adding Logs CUnit tests.\n");
CU_cleanup_registry();
return 1;
}

CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
fails = CU_get_number_of_failures();
CU_cleanup_registry();

return (int)fails;
}