Skip to content

Commit 1939ba6

Browse files
arifbalikdkalowsk
authored andcommitted
logging: backend: mqtt
Added MQTT logging backend Signed-off-by: Arif Balik <arifbalik@outlook.com>
1 parent 8b7b2b5 commit 1939ba6

File tree

5 files changed

+238
-0
lines changed

5 files changed

+238
-0
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) 2024 Arif Balik <arifbalik@outlook.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_LOGGING_LOG_BACKEND_MQTT_H_
8+
#define ZEPHYR_INCLUDE_LOGGING_LOG_BACKEND_MQTT_H_
9+
10+
#include <zephyr/net/mqtt.h>
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
/**
17+
* @brief MQTT log backend API
18+
* @defgroup log_backend_mqtt MQTT log backend API
19+
* @ingroup log_backend
20+
* @{
21+
*/
22+
23+
/**
24+
* @brief Set the MQTT client instance to be able to publish application's log messages to broker.
25+
*
26+
* This function allows the application to provide its own initialized
27+
* MQTT client to the log backend. The backend will use this client
28+
* exclusively for publishing log messages via mqtt_publish().
29+
*
30+
* @param client Pointer to an initialized and connected MQTT client.
31+
* The client must remain valid for the lifetime of the
32+
* log backend usage. Pass NULL to disable MQTT logging.
33+
*
34+
* @return 0 on success, negative error code on failure.
35+
*
36+
* @note The MQTT client must be connected before calling this function.
37+
* @note The backend will not manage the client connection - this is the
38+
* responsibility of the application.
39+
* @note The backend will only use mqtt_publish() and will not perform
40+
* any other operations on the client.
41+
*/
42+
int log_backend_mqtt_client_set(struct mqtt_client *client);
43+
44+
/**
45+
* @brief Set the MQTT topic to which log messages will be published.
46+
*
47+
* Allows the application to specify the MQTT topic that the log backend
48+
* will use for publishing log messages to.
49+
*
50+
* @param topic Pointer to a null-terminated string containing the MQTT topic.
51+
* The topic must remain valid for the lifetime of the log backend usage.
52+
*
53+
* @return 0 on success, negative error code on failure.
54+
*
55+
* @note The topic must be a valid UTF-8 string, null-terminated and should not exceed
56+
* the maximum length supported by the MQTT broker.
57+
*/
58+
int log_backend_mqtt_topic_set(const char *topic);
59+
60+
/**
61+
* @}
62+
*/
63+
64+
#ifdef __cplusplus
65+
}
66+
#endif
67+
68+
#endif /* ZEPHYR_INCLUDE_LOGGING_LOG_BACKEND_MQTT_H_ */

subsys/logging/backends/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ zephyr_sources_ifdef(
2525
log_backend_fs.c
2626
)
2727

28+
zephyr_sources_ifdef(
29+
CONFIG_LOG_BACKEND_MQTT
30+
log_backend_mqtt.c
31+
)
32+
2833
zephyr_sources_ifdef(
2934
CONFIG_LOG_BACKEND_NATIVE_POSIX
3035
log_backend_native_posix.c

subsys/logging/backends/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ rsource "Kconfig.adsp_mtrace"
88
rsource "Kconfig.ble"
99
rsource "Kconfig.efi_console"
1010
rsource "Kconfig.fs"
11+
rsource "Kconfig.mqtt"
1112
rsource "Kconfig.native_posix"
1213
rsource "Kconfig.net"
1314
rsource "Kconfig.ws"

subsys/logging/backends/Kconfig.mqtt

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright (c) 2024 Arif Balik <arifbalik@outlook.com>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config LOG_BACKEND_MQTT
5+
bool "MQTT backend"
6+
depends on MQTT_LIB && !LOG_MODE_IMMEDIATE
7+
help
8+
Send log messages to an MQTT broker using an external MQTT client.
9+
This backend publishes log messages to a configurable MQTT topic
10+
using an MQTT client provided by the application via the
11+
log_backend_mqtt_client_set() API. The application is responsible
12+
for initializing, connecting, and managing the MQTT client lifecycle.
13+
14+
if LOG_BACKEND_MQTT
15+
16+
config LOG_BACKEND_MQTT_TOPIC_DEFAULT
17+
string "Default MQTT topic for log messages"
18+
default "zephyr/logs"
19+
help
20+
Default MQTT topic for log messages. Use log backend MQTT API to change it at runtime.
21+
22+
config LOG_BACKEND_MQTT_QOS
23+
int "MQTT Quality of Service level"
24+
default 0
25+
range 0 2
26+
help
27+
QoS level for published log messages:
28+
0 - At most once delivery (fire and forget)
29+
1 - At least once delivery (acknowledged delivery)
30+
2 - Exactly once delivery (assured delivery)
31+
32+
config LOG_BACKEND_MQTT_RETAIN
33+
bool "Retain MQTT messages"
34+
help
35+
When enabled, published log messages will be retained by the broker
36+
and delivered to new subscribers immediately upon subscription.
37+
38+
config LOG_BACKEND_MQTT_MAX_MSG_SIZE
39+
int "Maximum log message size"
40+
default 256
41+
range 64 1024
42+
help
43+
Maximum size of a single log message in bytes.
44+
45+
backend = MQTT
46+
backend-str = mqtt
47+
source "subsys/logging/Kconfig.template.log_format_config"
48+
49+
endif # LOG_BACKEND_MQTT
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright (c) 2024 Arif Balik <arifbalik@outlook.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/logging/log.h>
8+
LOG_MODULE_REGISTER(log_backend_mqtt, CONFIG_LOG_DEFAULT_LEVEL);
9+
10+
#include <zephyr/kernel.h>
11+
#include <zephyr/logging/log_backend.h>
12+
#include <zephyr/logging/log_ctrl.h>
13+
#include <zephyr/logging/log_backend_std.h>
14+
#include <zephyr/logging/log_backend_mqtt.h>
15+
#include <zephyr/logging/log_core.h>
16+
#include <zephyr/logging/log_output.h>
17+
#include <zephyr/net/mqtt.h>
18+
#include <zephyr/sys/util.h>
19+
#include <zephyr/random/random.h>
20+
21+
#include <string.h>
22+
#include <errno.h>
23+
24+
static bool panic;
25+
static char *mqtt_topic = CONFIG_LOG_BACKEND_MQTT_TOPIC_DEFAULT;
26+
static uint8_t log_buf[CONFIG_LOG_BACKEND_MQTT_MAX_MSG_SIZE];
27+
static uint32_t log_format_current = CONFIG_LOG_BACKEND_MQTT_OUTPUT_DEFAULT;
28+
29+
static int log_output_func(uint8_t *data, size_t length, void *output_ctx)
30+
{
31+
__ASSERT(output_ctx != NULL, "Output context must not be NULL");
32+
33+
struct mqtt_client *client = (struct mqtt_client *)output_ctx;
34+
struct mqtt_publish_param param = {0};
35+
36+
param.message.topic.topic.utf8 = (uint8_t *)mqtt_topic;
37+
param.message.topic.topic.size = strlen(mqtt_topic);
38+
param.message.topic.qos = CONFIG_LOG_BACKEND_MQTT_QOS;
39+
param.message.payload.data = data;
40+
param.message.payload.len = length;
41+
param.retain_flag = IS_ENABLED(CONFIG_LOG_BACKEND_MQTT_RETAIN);
42+
43+
#if (CONFIG_LOG_BACKEND_MQTT_QOS > MQTT_QOS_0_AT_MOST_ONCE)
44+
param.message_id = sys_rand32_get();
45+
#endif
46+
47+
int ret = mqtt_publish(client, &param);
48+
49+
if (ret != 0) {
50+
return ret;
51+
}
52+
53+
return length;
54+
}
55+
56+
LOG_OUTPUT_DEFINE(log_output_mqtt, log_output_func, log_buf, sizeof(log_buf));
57+
58+
static void mqtt_backend_process(const struct log_backend *const backend,
59+
union log_msg_generic *msg)
60+
{
61+
if (panic) {
62+
return;
63+
}
64+
65+
uint32_t flags = log_backend_std_get_flags();
66+
67+
log_format_func_t log_output_func = log_format_func_t_get(log_format_current);
68+
69+
log_output_ctx_set(&log_output_mqtt, backend->cb->ctx);
70+
71+
log_output_func(&log_output_mqtt, &msg->log, flags);
72+
}
73+
74+
static int mqtt_backend_format_set(const struct log_backend *const backend, uint32_t log_type)
75+
{
76+
ARG_UNUSED(backend);
77+
log_format_current = log_type;
78+
return 0;
79+
}
80+
81+
static void mqtt_backend_panic(const struct log_backend *const backend)
82+
{
83+
ARG_UNUSED(backend);
84+
panic = true;
85+
}
86+
87+
const struct log_backend_api log_backend_mqtt_api = {
88+
.process = mqtt_backend_process,
89+
.format_set = mqtt_backend_format_set,
90+
.panic = mqtt_backend_panic,
91+
};
92+
93+
LOG_BACKEND_DEFINE(log_backend_mqtt, log_backend_mqtt_api, false);
94+
95+
int log_backend_mqtt_client_set(struct mqtt_client *client)
96+
{
97+
log_backend_disable(&log_backend_mqtt);
98+
99+
if (client != NULL) {
100+
log_backend_enable(&log_backend_mqtt, (void *)client, CONFIG_LOG_MAX_LEVEL);
101+
}
102+
103+
return 0;
104+
}
105+
106+
int log_backend_mqtt_topic_set(const char *topic)
107+
{
108+
if (topic == NULL || strlen(topic) == 0) {
109+
return -EINVAL;
110+
}
111+
112+
mqtt_topic = topic;
113+
114+
return 0;
115+
}

0 commit comments

Comments
 (0)