Example client lifetime and payload size stat plugins.

pull/2438/head
Roger A. Light 4 years ago
parent 9cffbe0928
commit 5b2e181c9f

@ -16,6 +16,13 @@ This is an **example** plugin that demonstrates a basic authentication callback
that allows clients based on their IP address. Password based authentication is
preferred over this very simple type of access control.
## Examples / Client lifetime stats
This is an **example** plugin that collects counts of how long client sessions
last, in different time buckets of 0, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1k,
2k, 5k, 10k, 20k, 50k, 100k, 200k, 500k, 1M, 2M, 5M, 10M, 20M, 50M, 100M, 200M,
500M seconds. It periodically publishes the counts at
`$SYS/broker/client/lifetimes/<bucket>`.
## Examples / Client properties
This is an **example** plugin that demonstrates some of the functions for
retrieving client information such as client id and username.
@ -56,6 +63,12 @@ This plugin adds the text string "hello " to the beginning of each payload, so
with anything other than simple plain text messages it will corrupt the payload
contents.
## Examples / Payload size stats
This is an **example** plugin that collects counts of payload message sizes, in
time buckets of 0, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1k, 2k, 5k, 10k, 20k,
50k, 100k, 200k, 500k, 1M, 2M, 5M, 10M, 20M, 50M, 100M, 200M, 500M bytes. It
periodically publishes the counts at `$SYS/broker/publish/sizes/<bucket>`.
## Examples / Print IP on publish
This is an **example** plugin that prints out client ID and IP address of any
client that publishes on a particular topic.

@ -1,5 +1,6 @@
if(NOT WIN32)
add_subdirectory(add-properties)
add_subdirectory(client-lifetime-stats)
add_subdirectory(message-timestamp)
endif()
add_subdirectory(auth-by-ip)
@ -8,5 +9,6 @@ add_subdirectory(connection-state)
add_subdirectory(delayed-auth)
add_subdirectory(force-retain)
add_subdirectory(payload-modification)
add_subdirectory(payload-size-stats)
add_subdirectory(print-ip-on-publish)
add_subdirectory(topic-modification)

@ -1,12 +1,14 @@
DIRS= \
add-properties \
auth-by-ip \
client-lifetime-stats \
client-properties \
connection-state \
delayed-auth \
force-retain \
message-timestamp \
payload-modification \
payload-size-stats \
print-ip-on-publish \
topic-modification \
wildcard-temp

@ -0,0 +1,27 @@
set (PLUGIN_NAME mosquitto_client_lifetime_stats)
add_library(${PLUGIN_NAME} MODULE
${PLUGIN_NAME}.c
)
target_include_directories(${PLUGIN_NAME} PRIVATE
"${OPENSSL_INCLUDE_DIR}"
"${STDBOOL_H_PATH}"
"${STDINT_H_PATH}"
"${mosquitto_SOURCE_DIR}"
"${mosquitto_SOURCE_DIR}/deps"
"${mosquitto_SOURCE_DIR}/include"
)
link_directories(${mosquitto_SOURCE_DIR})
set_target_properties(${PLUGIN_NAME} PROPERTIES
PREFIX ""
POSITION_INDEPENDENT_CODE 1
)
if(WIN32)
target_link_libraries(${PLUGIN_NAME} mosquitto)
endif()
# Don't install, these are example plugins only.
#install(TARGETS ${PLUGIN_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")

@ -0,0 +1,28 @@
include ../../../config.mk
.PHONY : all binary check clean reallyclean test install uninstall
PLUGIN_NAME=mosquitto_client_lifetime_stats
PLUGIN_CFLAGS+=-I../../../include -I../../../ -I../../../deps
all : binary
binary : ${PLUGIN_NAME}.so
${PLUGIN_NAME}.so : ${PLUGIN_NAME}.c
$(CROSS_COMPILE)$(CC) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) $(PLUGIN_LDFLAGS) -fPIC -shared $< -o $@
reallyclean : clean
clean:
-rm -f *.o ${PLUGIN_NAME}.so *.gcda *.gcno
check: test
test:
install: ${PLUGIN_NAME}.so
# Don't install, these are examples only.
$(INSTALL) -d "${DESTDIR}$(libdir)"
$(INSTALL) ${STRIP_OPTS} ${PLUGIN_NAME}.so "${DESTDIR}${libdir}/${PLUGIN_NAME}.so"
uninstall :
-rm -f "${DESTDIR}${libdir}/${PLUGIN_NAME}.so"

@ -0,0 +1,197 @@
/*
Copyright (c) 2021 Roger Light <roger@atchoo.org>
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
/*
* Publish statistics on client session lifetimes.
*
* Compile with:
* gcc -I<path to mosquitto-repo/include> -fPIC -shared mosquitto_client_lifetime_stats.c -o mosquitto_client_lifetime_stats.so
*
* Use in config with:
*
* plugin /path/to/mosquitto_client_lifetime_stats.so
*
* Note that this only works on Mosquitto 2.0 or later.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <uthash.h>
#include "mosquitto_broker.h"
#include "mosquitto_plugin.h"
#include "mosquitto.h"
#include "mqtt_protocol.h"
MOSQUITTO_PLUGIN_DECLARE_VERSION(5);
static mosquitto_plugin_id_t *mosq_pid = NULL;
struct lifetime_s{
UT_hash_handle hh;
char *id;
time_t connect;
};
struct lifetime_s *local_lifetimes = NULL;
#define LIFETIME_COUNT 28
static const char *lifetime_strs[LIFETIME_COUNT] = {
"0",
"1", "2", "5",
"10", "20", "50",
"100", "200", "500",
"1k", "2k", "5k",
"10k", "20k", "50k",
"100k", "200k", "500k",
"1M", "2M", "5M",
"10M", "20M", "50M",
"100M", "200M", "500M"
};
static uint32_t lifetime_values[LIFETIME_COUNT] = {
0,
1, 2, 5,
10, 20, 50,
100, 200, 500,
1000, 2000, 5000,
10000, 20000, 50000,
100000, 200000, 500000,
1000000, 2000000, 5000000,
10000000, 20000000, 50000000,
100000000, 200000000, 500000000
};
static long lifetime_counts[LIFETIME_COUNT];
static long last_lifetime_counts[LIFETIME_COUNT];
static time_t last_report = 0;
static int callback_tick(int event, void *event_data, void *userdata)
{
struct timespec ts;
char topic[40];
char payload[40];
int slen;
int i;
UNUSED(event);
UNUSED(event_data);
UNUSED(userdata);
clock_gettime(CLOCK_REALTIME, &ts);
if(last_report + 10 < ts.tv_sec){
last_report = ts.tv_sec;
for(i=0; i<LIFETIME_COUNT; i++){
if(lifetime_counts[i] != last_lifetime_counts[i]){
snprintf(topic, sizeof(topic), "$SYS/broker/client/lifetimes/%s", lifetime_strs[i]);
slen = snprintf(payload, sizeof(payload), "%ld", lifetime_counts[i]);
mosquitto_broker_publish_copy(NULL, topic, slen, payload, 0, 1, NULL);
last_lifetime_counts[i] = lifetime_counts[i];
}
}
}
return MOSQ_ERR_SUCCESS;
}
static int callback_connect(int event, void *event_data, void *userdata)
{
struct mosquitto_evt_connect *ed = event_data;
const char *id;
struct lifetime_s *client;
UNUSED(event);
UNUSED(userdata);
id = mosquitto_client_id(ed->client);
if(id){
HASH_FIND(hh, local_lifetimes, id, strlen(id), client);
if(!client){
client = malloc(sizeof(struct lifetime_s));
if(client == NULL){
return MOSQ_ERR_SUCCESS;
}
client->id = strdup(id);
if(client->id == NULL){
free(client);
return MOSQ_ERR_SUCCESS;
}
client->connect = time(NULL);
HASH_ADD_KEYPTR(hh, local_lifetimes, client->id, strlen(client->id), client);
}
}
return MOSQ_ERR_SUCCESS;
}
static int callback_disconnect(int event, void *event_data, void *userdata)
{
struct mosquitto_evt_disconnect *ed = event_data;
int i;
const char *id;
struct lifetime_s *client;
time_t lifetime;
UNUSED(event);
UNUSED(userdata);
id = mosquitto_client_id(ed->client);
if(id){
HASH_FIND(hh, local_lifetimes, id, strlen(id), client);
if(client){
HASH_DELETE(hh, local_lifetimes, client);
lifetime = time(NULL) - client->connect;
free(client->id);
free(client);
for(i=0; i<LIFETIME_COUNT; i++){
if(lifetime <= lifetime_values[i]){
lifetime_counts[i]++;
break;
}
}
}
}
return MOSQ_ERR_SUCCESS;
}
int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *opts, int opt_count)
{
UNUSED(user_data);
UNUSED(opts);
UNUSED(opt_count);
memset(lifetime_counts, 0, sizeof(lifetime_counts));
memset(last_lifetime_counts, 0, sizeof(last_lifetime_counts));
mosq_pid = identifier;
mosquitto_callback_register(mosq_pid, MOSQ_EVT_CONNECT, callback_connect, NULL, NULL);
mosquitto_callback_register(mosq_pid, MOSQ_EVT_DISCONNECT, callback_disconnect, NULL, NULL);
mosquitto_callback_register(mosq_pid, MOSQ_EVT_TICK, callback_tick, NULL, NULL);
return MOSQ_ERR_SUCCESS;
}

@ -0,0 +1 @@
plugin ./mosquitto_client_lifetime_stats.so

@ -0,0 +1,3 @@
#!/bin/sh
../../../src/mosquitto -c test.conf -v

@ -13,7 +13,7 @@ target_include_directories(${PLUGIN_NAME} PRIVATE
if(WITH_BUNDLED_DEPS)
target_include_directories(${PLUGIN_NAME} PRIVATE
"${${PLUGIN_NAME}}/deps"
"${mosquitto_SOURCE_DIR}/deps"
)
endif()

@ -0,0 +1,26 @@
set (PLUGIN_NAME mosquitto_payload_size_stats)
add_library(${PLUGIN_NAME} MODULE
${PLUGIN_NAME}.c
)
target_include_directories(${PLUGIN_NAME} PRIVATE
"${OPENSSL_INCLUDE_DIR}"
"${STDBOOL_H_PATH}"
"${STDINT_H_PATH}"
"${mosquitto_SOURCE_DIR}"
"${mosquitto_SOURCE_DIR}/include"
)
link_directories(${mosquitto_SOURCE_DIR})
set_target_properties(${PLUGIN_NAME} PROPERTIES
PREFIX ""
POSITION_INDEPENDENT_CODE 1
)
if(WIN32)
target_link_libraries(${PLUGIN_NAME} mosquitto)
endif()
# Don't install, these are example plugins only.
#install(TARGETS ${PLUGIN_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")

@ -0,0 +1,28 @@
include ../../../config.mk
.PHONY : all binary check clean reallyclean test install uninstall
PLUGIN_NAME=mosquitto_payload_size_stats
PLUGIN_CFLAGS+=-I../../../include -I../../../
all : binary
binary : ${PLUGIN_NAME}.so
${PLUGIN_NAME}.so : ${PLUGIN_NAME}.c
$(CROSS_COMPILE)$(CC) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) $(PLUGIN_LDFLAGS) -fPIC -shared $< -o $@
reallyclean : clean
clean:
-rm -f *.o ${PLUGIN_NAME}.so *.gcda *.gcno
check: test
test:
install: ${PLUGIN_NAME}.so
# Don't install, these are examples only.
#$(INSTALL) -d "${DESTDIR}$(libdir)"
#$(INSTALL) ${STRIP_OPTS} ${PLUGIN_NAME}.so "${DESTDIR}${libdir}/${PLUGIN_NAME}.so"
uninstall :
-rm -f "${DESTDIR}${libdir}/${PLUGIN_NAME}.so"

@ -0,0 +1,141 @@
/*
Copyright (c) 2021 Roger Light <roger@atchoo.org>
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
https://www.eclipse.org/legal/epl-2.0/
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Roger Light - initial implementation and documentation.
*/
/*
* Publish statistics on message payload size.
*
* Compile with:
* gcc -I<path to mosquitto-repo/include> -fPIC -shared mosquitto_payload_size_stats.c -o mosquitto_payload_size_stats.so
*
* Use in config with:
*
* plugin /path/to/mosquitto_payload_size_stats.so
*
* Note that this only works on Mosquitto 2.0 or later.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mosquitto_broker.h"
#include "mosquitto_plugin.h"
#include "mosquitto.h"
#include "mqtt_protocol.h"
MOSQUITTO_PLUGIN_DECLARE_VERSION(5);
static mosquitto_plugin_id_t *mosq_pid = NULL;
#define SIZE_COUNT 28
static const char *size_strs[SIZE_COUNT] = {
"0",
"1", "2", "5",
"10", "20", "50",
"100", "200", "500",
"1k", "2k", "5k",
"10k", "20k", "50k",
"100k", "200k", "500k",
"1M", "2M", "5M",
"10M", "20M", "50M",
"100M", "200M", "500M"
};
static uint32_t size_values[SIZE_COUNT] = {
0,
1, 2, 5,
10, 20, 50,
100, 200, 500,
1000, 2000, 5000,
10000, 20000, 50000,
100000, 200000, 500000,
1000000, 2000000, 5000000,
10000000, 20000000, 50000000,
100000000, 200000000, 500000000
};
static long size_counts[SIZE_COUNT];
static long last_size_counts[SIZE_COUNT];
static time_t last_report = 0;
static int callback_tick(int event, void *event_data, void *userdata)
{
struct timespec ts;
char topic[40];
char payload[40];
int slen;
int i;
UNUSED(event);
UNUSED(event_data);
UNUSED(userdata);
clock_gettime(CLOCK_REALTIME, &ts);
if(last_report + 10 < ts.tv_sec){
last_report = ts.tv_sec;
for(i=0; i<SIZE_COUNT; i++){
if(size_counts[i] != last_size_counts[i]){
snprintf(topic, sizeof(topic), "$SYS/broker/publish/sizes/%s", size_strs[i]);
slen = snprintf(payload, sizeof(payload), "%ld", size_counts[i]);
mosquitto_broker_publish_copy(NULL, topic, slen, payload, 0, 1, NULL);
last_size_counts[i] = size_counts[i];
}
}
}
return MOSQ_ERR_SUCCESS;
}
static int callback_message(int event, void *event_data, void *userdata)
{
struct mosquitto_evt_message *ed = event_data;
int i;
UNUSED(event);
UNUSED(userdata);
for(i=0; i<SIZE_COUNT; i++){
if(ed->payloadlen <= size_values[i]){
size_counts[i]++;
break;
}
}
return MOSQ_ERR_SUCCESS;
}
int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *opts, int opt_count)
{
UNUSED(user_data);
UNUSED(opts);
UNUSED(opt_count);
memset(size_counts, 0, sizeof(size_counts));
memset(last_size_counts, 0, sizeof(last_size_counts));
mosq_pid = identifier;
mosquitto_callback_register(mosq_pid, MOSQ_EVT_MESSAGE, callback_message, NULL, NULL);
mosquitto_callback_register(mosq_pid, MOSQ_EVT_TICK, callback_tick, NULL, NULL);
return MOSQ_ERR_SUCCESS;
}

@ -0,0 +1 @@
plugin ./mosquitto_payload_size_stats.so

@ -0,0 +1,3 @@
#!/bin/sh
../../../src/mosquitto -c test.conf -v
Loading…
Cancel
Save