-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This example disables Boost.Log and uses simple std::log. Updated document.
- Loading branch information
Showing
10 changed files
with
360 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,113 @@ | ||
= logging | ||
= Logging | ||
|
||
async_mqtt supports Boost.Log style logging. The severity levels are `fatal`, `error`, `warning`, `info`, `debug`, and `trace`. | ||
== Using Boost.Log | ||
`async_mqtt` provides logging support with Boost.Log. Supported severity levels include `fatal`, `error`, `warning`, `info`, `debug`, and `trace`. | ||
|
||
The easiest way to setup logging is | ||
To quickly set up logging, you can use: | ||
|
||
```cpp | ||
async_mqtt::setup_log( | ||
async_mqtt::severity_level::info, // you can use any other severity_level | ||
true // if true or omit the argument | ||
// log is colored, otherwise non colored | ||
async_mqtt::severity_level::info, // Choose any severity level | ||
true // Pass `true` or omit to enable colored output | ||
); | ||
``` | ||
|
||
You can setup your custom settings. | ||
Custom configurations are also supported. | ||
|
||
See https://github.com/redboltz/async_mqtt/blob/main/include/async_mqtt/util/setup_log.hpp[setup_log.hpp] | ||
See `setup_log.hpp` for details: https://github.com/redboltz/async_mqtt/blob/main/include/async_mqtt/util/setup_log.hpp[setup_log.hpp] | ||
|
||
NOTE: Boost.Log-based logging is enabled when `ASYNC_MQTT_USE_LOG` is defined. For more information, see xref:config.adoc[] | ||
|
||
=== Compile time severity filtering | ||
|
||
`setup_log()` is for runtime severity level setting. | ||
|
||
`ASYNC_MQTT_LOG_SEV` is for compile-time severity level setting. | ||
If you define as follows: | ||
|
||
```cpp | ||
#define ASYNC_MQTT_LOG_SEV info | ||
``` | ||
|
||
then, `fatal`, `error`, `warning`, and `info` logs are compiled. `debug` and `trace` logs are erased from the code. | ||
It is useful for minimal code generation for logging. | ||
|
||
== Using a Custom Logger | ||
Boost.Log offers extensive functionality, including logging to the console, syslog, and files. However, some users may prefer a simpler logging mechanism. | ||
|
||
All you need to do is defining two macros. | ||
One is `ASYNC_MQTT_ADD_VALUE`, the other is `ASYNC_MQTT_LOG`. | ||
|
||
To create and use a custom logger, follow these steps: | ||
|
||
All steps should be completed before including any `async_mqtt` headers. | ||
|
||
Include the minimal header to implement your custom logger: | ||
|
||
```cpp | ||
#include <async_mqtt/util/log_severity.hpp> | ||
``` | ||
|
||
[Optional] Remove the `ASYNC_MQTT_USE_LOG` definition: | ||
|
||
```cpp | ||
#undef ASYNC_MQTT_USE_LOG | ||
``` | ||
|
||
NOTE: Even if `ASYNC_MQTT_USE_LOG` is defined, your custom logger works well. But removing Boost.Log is often the one of the dominant motivation to introduce custom loggers. | ||
|
||
Define your custom logger class: | ||
|
||
```cpp | ||
// Define logger class | ||
struct custom_log { | ||
explicit constexpr custom_log( | ||
std::string chan, // chan indicates the log channel or part | ||
async_mqtt::severity_level sev // sev represents the severity level | ||
) | ||
{ | ||
// Setup filter | ||
if (sev < async_mqtt::severity_level::info) { | ||
print = false; | ||
return; | ||
} | ||
// Output header | ||
std::clog << "[" << sev << "]" << "(" << chan << ") "; | ||
} | ||
~custom_log() { | ||
// Output trailer | ||
if (print) std::clog << std::endl; | ||
} | ||
|
||
bool print = true; | ||
}; | ||
|
||
// Define output stream operator | ||
template <typename T> | ||
inline constexpr custom_log const& operator<<( | ||
custom_log const& o, | ||
T const& t | ||
) { | ||
// Output message body with filter | ||
if (o.print) std::clog << t; | ||
return o; | ||
} | ||
``` | ||
|
||
NOTE: This example demonstrates how to locate logging elements in the output. e.g.) channel, severity, tag, ... , so different type of brace is intentionally used. (`()<>{}`) | ||
|
||
|
||
Apply the custom logger to the `ASYNC_MQTT_LOG()` macro. The `ASYNC_MQTT_LOG()` macro is used throughout the `async_mqtt` library. | ||
|
||
```cpp | ||
// Output additional value. Stringized name(tag) and tagged value. | ||
#define ASYNC_MQTT_ADD_VALUE(name, val) "<" << #name ">{" << val << "} " | ||
``` | ||
|
||
```cpp | ||
// Set ASYNC_MQTT_LOG macro to custom_log. | ||
#define ASYNC_MQTT_LOG(chan, sev) custom_log(chan, async_mqtt::severity_level::sev) | ||
``` | ||
|
||
=== Example | ||
For a full example, see link:../example/custom_logger.cpp[custom_logger.cpp]. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
// Copyright Takatoshi Kondo 2023 | ||
// | ||
// Distributed under the Boost Software License, Version 1.0. | ||
// (See accompanying file LICENSE_1_0.txt or copy at | ||
// http://www.boost.org/LICENSE_1_0.txt) | ||
|
||
// This example connects to the specified MQTT broker. | ||
// It then publishes to topic1, topic2, and topic3, and receives the publish results. | ||
// Finally, it disconnects from the broker. | ||
// | ||
// Example: | ||
// ./custom_logger_pub mqtt.redboltz.net 1883 | ||
|
||
#include <iostream> | ||
#include <string> | ||
|
||
#include <boost/asio.hpp> | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
// Using custom logger BEGIN | ||
|
||
// Implement the following codes before any async_mqtt headers include. | ||
// Exception: | ||
// async_mqtt/util/log_severity.hpp is used for defining custom_log | ||
|
||
#include <async_mqtt/util/log_severity.hpp> | ||
|
||
// Optional: | ||
// Define custom logger instead of Boost.Log (default) | ||
// undef ASYNC_MQTT_USE_LOG or remove from compiler option | ||
// -DASYNC_MQTT_USE_LOG removes all Boost.Log related code. | ||
// It can compile faster. | ||
#undef ASYNC_MQTT_USE_LOG | ||
|
||
// Define simple custom logger | ||
// This is example implementation. | ||
// Just output channel, sevarity, and message body to std::clog | ||
struct custom_log { | ||
explicit constexpr custom_log(std::string_view chan, async_mqtt::severity_level sev) | ||
{ | ||
// Setup filter | ||
if (sev < async_mqtt::severity_level::info) { | ||
print = false; | ||
return; | ||
} | ||
// Output header | ||
std::clog << "[" << sev << "]" << "(" << chan << ") "; | ||
} | ||
~custom_log() { | ||
// Output trailer | ||
if (print) std::clog << std::endl; | ||
} | ||
|
||
bool print = true; | ||
}; | ||
|
||
template <typename T> | ||
inline constexpr custom_log const& operator<<( | ||
custom_log const& o, | ||
T const& t | ||
) { | ||
// Output message body with filter | ||
if (o.print) std::clog << t; | ||
return o; | ||
} | ||
|
||
// Output additional value. Stringized name(tag) and tagged value. | ||
#define ASYNC_MQTT_ADD_VALUE(name, val) "<" << #name ">{" << val << "} " | ||
|
||
// Set ASYNC_MQTT_LOG macro to custom_log. | ||
#define ASYNC_MQTT_LOG(chan, sev) custom_log(chan, async_mqtt::severity_level::sev) | ||
|
||
// Using custom logger END | ||
//////////////////////////////////////////////////////////////////////////////// | ||
|
||
// The following code is the same as cl_cpp17_mqtt_pub.cpp | ||
|
||
#include <async_mqtt/all.hpp> | ||
|
||
|
||
namespace as = boost::asio; | ||
namespace am = async_mqtt; | ||
|
||
using client_t = am::client<am::protocol_version::v5, am::protocol::mqtt>; | ||
|
||
struct app { | ||
app(as::any_io_executor exe, std::string_view host, std::string_view port) | ||
: cli_{exe} | ||
{ | ||
am::async_underlying_handshake( | ||
cli_.next_layer(), | ||
host, | ||
port, | ||
[this](auto&&... args) { | ||
handle_underlying_handshake( | ||
std::forward<std::remove_reference_t<decltype(args)>>(args)... | ||
); | ||
} | ||
); | ||
} | ||
|
||
private: | ||
void handle_underlying_handshake( | ||
am::error_code ec | ||
) { | ||
std::cout << "underlying_handshake:" << ec.message() << std::endl; | ||
if (ec) return; | ||
cli_.async_start( | ||
true, // clean_start | ||
std::uint16_t(0), // keep_alive | ||
"", // Client Identifier, empty means generated by the broker | ||
std::nullopt, // will | ||
"UserName1", | ||
"Password1", | ||
[this](auto&&... args) { | ||
handle_start_response(std::forward<decltype(args)>(args)...); | ||
} | ||
); | ||
} | ||
|
||
void handle_start_response( | ||
am::error_code ec, | ||
std::optional<client_t::connack_packet> connack_opt | ||
) { | ||
std::cout << "start:" << ec.message() << std::endl; | ||
if (ec) return; | ||
if (connack_opt) { | ||
std::cout << *connack_opt << std::endl; | ||
cli_.async_publish( | ||
"topic1", | ||
"payload1", | ||
am::qos::at_most_once, | ||
[this](auto&&... args) { | ||
handle_publish_response( | ||
std::forward<std::remove_reference_t<decltype(args)>>(args)... | ||
); | ||
} | ||
); | ||
cli_.async_publish( | ||
*cli_.acquire_unique_packet_id(), // sync version only works thread safe context | ||
"topic2", | ||
"payload2", | ||
am::qos::at_least_once, | ||
[this](auto&&... args) { | ||
handle_publish_response( | ||
std::forward<std::remove_reference_t<decltype(args)>>(args)... | ||
); | ||
} | ||
); | ||
cli_.async_publish( | ||
*cli_.acquire_unique_packet_id(), // sync version only works thread safe context | ||
"topic3", | ||
"payload3", | ||
am::qos::exactly_once, | ||
[this](auto&&... args) { | ||
handle_publish_response( | ||
std::forward<std::remove_reference_t<decltype(args)>>(args)... | ||
); | ||
} | ||
); | ||
} | ||
} | ||
|
||
void handle_publish_response( | ||
am::error_code ec, | ||
client_t::pubres_type pubres | ||
) { | ||
std::cout << "publish:" << ec.message() << std::endl; | ||
if (ec) return; | ||
if (pubres.puback_opt) { | ||
std::cout << *pubres.puback_opt << std::endl; | ||
} | ||
if (pubres.pubrec_opt) { | ||
std::cout << *pubres.pubrec_opt << std::endl; | ||
} | ||
if (pubres.pubcomp_opt) { | ||
std::cout << *pubres.pubcomp_opt << std::endl; | ||
cli_.async_disconnect(as::detached); | ||
} | ||
} | ||
|
||
client_t cli_; | ||
}; | ||
|
||
int main(int argc, char* argv[]) { | ||
am::setup_log( | ||
am::severity_level::warning, | ||
true // log colored | ||
); | ||
if (argc != 3) { | ||
std::cout << "Usage: " << argv[0] << " host port" << std::endl; | ||
return -1; | ||
} | ||
as::io_context ioc; | ||
app a{ioc.get_executor(), argv[1], argv[2]}; | ||
ioc.run(); | ||
} |
Oops, something went wrong.