diff --git a/README.md b/README.md index ce233ce..6a32fd8 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,37 @@ void loop() { } ``` +## Using the logging API + +As an addon to the Ubsub API, there is also a simple logging API +to help you send out log messages to ubsub (in additional to serial/stdout). + +### Configuration +``` +ULOG_DISABLE Disable all logging if defined (macro to nothing) +ULOG_BUF_SIZE Override default buffer size (default: 512) +ULOG_TOPIC Override topic to write log messages to (default: "log") +ULOG_SERIAL Enable serial output (or stdout if unix) +ULOG_DEBUG If defined, will enable UDEBUG macro output +``` + +### Example +```cpp +#include "ubsub_log.h" + +void setup() { + initUbsubLogger("id", "key"); + + // If you already have an ubsub instance: + // initUbsubLogger(&ubsub); + + ULOG("hi there %s", "name"); + UWARN("..."); + UERROR("..."); + UDEBUG("..."); +} +``` + # API ## Ubsub(const char* deviceId, const char* deviceKey) diff --git a/examples/unix/main.cpp b/examples/unix/main.cpp index 0732a8b..28c22c2 100644 --- a/examples/unix/main.cpp +++ b/examples/unix/main.cpp @@ -1,6 +1,7 @@ #include #include #include "../../src/ubsub.h" +#include "../../src/ubsub_log.h" void myMethod(const char* arg) { std::cout << "RECEIVED: " << arg << std::endl; @@ -13,8 +14,12 @@ int main() { if (!client.connect(2)) { std::cout << "Failed to connect" << std::endl; } + initUbsubLogger(&client); + // setLoggerDeviceId("test"); // client.enableAutoRetry(false); + UINFO("Welcome to the logging test!"); + client.listenToTopic("testy", myMethod); client.publishEvent("Byg2kKB3SZ", "HJ3ytS3SW", "Hi there"); @@ -27,6 +32,8 @@ int main() { client.watchVariable("other", &test); client.watchVariable("var", &test); // Any time this value changes, an event will be emitted + UWARN("Done with watch %d", test); + while(true) { test++; client.processEvents(); diff --git a/src/ubsub_log.h b/src/ubsub_log.h new file mode 100644 index 0000000..bfbb18b --- /dev/null +++ b/src/ubsub_log.h @@ -0,0 +1,114 @@ +/** +Ubsub log wrapper to send log events to ubsub (or other sources) + +Configuration: +ULOG_DISABLE Disable all logging if defined (macro to nothing) +ULOG_BUF_SIZE Override default buffer size (default: 512) +ULOG_TOPIC Override topic to write log messages to (default: "log") +ULOG_SERIAL Enable serial output (or stdout if unix) +ULOG_DEBUG If defined, will enable UDEBUG macro output +**/ + +#ifndef ubsub_log_h +#define ubsub_log_h + +#ifndef ULOG_DISABLE + + #if (!ARDUINO || PARTICLE) + #include + #include + #include + #else + #warning Logs are enabled on IoT device, may consume extra string memory! + #include + #endif + #include + #include "ubsub.h" + #include "minijson.h" + + #ifndef ULOG_BUF_SIZE + #define ULOG_BUF_SIZE 512 + #endif + + #ifndef ULOG_TOPIC + #define ULOG_TOPIC "log" + #endif + + static const char* _deviceId = NULL; + static Ubsub* _conn = NULL; + + void initUbsubLogger(const char *deviceId, const char *deviceKey) { + if (_conn == NULL) { + _conn = new Ubsub(deviceId, deviceKey); + _conn->enableAutoRetry(false); + _conn->connect(); + } + } + void initUbsubLogger(Ubsub* conn) { + _conn = conn; + } + void setLoggerDeviceId(const char* deviceId) { + _deviceId = strdup(deviceId); + } + void shutdownLogger() { + if (_conn != NULL) { + delete _conn; + _conn = NULL; + } + } + + static void writeULog(const char* level, const char* filename, int line, const char* msg, ...) { + static char logbuf[ULOG_BUF_SIZE]; + va_list argptr; + va_start(argptr, msg); + vsnprintf(logbuf, sizeof(logbuf), msg, argptr); + va_end(argptr); + + #ifdef ULOG_SERIAL + #if ARDUINO || PARTICLE + Serial.printf("[%s] (%s:%d) %s\n", level, filename, line, logbuf); + Serial.flush(); + #else + std::cerr << "[" << level << "] (" << filename << ":" << line << ") " << logbuf << std::endl; + #endif + #endif + + if (_conn != NULL) { + char jsonBuf[ULOG_BUF_SIZE]; // Buffer on stack + MiniJsonBuilder json(jsonBuf, ULOG_BUF_SIZE); + json.open() + .write("level", level) + .write("filename", filename) + .write("line", line) + .write("msg", logbuf); + if (_deviceId != NULL) { + json.write("device", _deviceId); + } + json.close(); + + _conn->callFunction(ULOG_TOPIC, json.c_str()); + } + } + + #define UINFO(msg, ...) writeULog("INFO", __FILE__, __LINE__, msg, ## __VA_ARGS__) + #define UWARN(msg, ...) writeULog("WARN", __FILE__, __LINE__, msg, ## __VA_ARGS__) + #define UERROR(msg, ...) writeULog("ERROR", __FILE__, __LINE__, msg, ## __VA_ARGS__) + #ifdef ULOG_DEBUG + #define UDEBUG(msg, ...) writeULog("DEBUG", __FILE__, __LINE__, msg, ## __VA_ARGS__) + #else + #define UDEBUG(msg, ...) + #endif + +#else + // Ubsub log disabled, nullify log statements + #define initUbsubLogger + #define setLoggerDeviceId + #define shutdownLogger + + #define UINFO(msg, ...) + #define UWARN(msg, ...) + #define UERROR(msg, ...) + #define UDEBUG(msg, ...) +#endif + +#endif