Runtime logging configuration#1748
Conversation
1d8cca4 to
8d12d4b
Compare
1259cae to
36fb798
Compare
|
|
||
| namespace control { | ||
|
|
||
| namespace diagnostics { |
There was a problem hiding this comment.
The diagnostics namespace seems a little strange..can you add a comment about the reasoning behind the naming?
| return SYSTEM_ERROR_NOT_SUPPORTED; | ||
| } | ||
| int log_config(int command, const void* command_data, void* command_result) { | ||
| CHECK_TRUE(g_logConfigCallback, SYSTEM_ERROR_NOT_SUPPORTED); |
There was a problem hiding this comment.
Nice! 👍 I'd love something like this to be included in the CHECK macro docs so that we can help educate that this is useful for parameter or state validation, with the benefit of logging/checkpoints etc.
| const DecodedCString idStr(&pbReq.id); | ||
| Filters f; | ||
| pbReq.filters.arg = &f; | ||
| pbReq.filters.funcs.decode = [](pb_istream_t* strm, const pb_field_t* field, void** arg) { |
There was a problem hiding this comment.
A link to the documentation for the mechanism used by protobuf here to do the decoding would be helpful. This stuff is pretty cryptic if you are not working closely with it.
| Filters f; | ||
| pbReq.filters.arg = &f; | ||
| pbReq.filters.funcs.decode = [](pb_istream_t* strm, const pb_field_t* field, void** arg) { | ||
| const auto f = (Filters*)*arg; |
There was a problem hiding this comment.
Would it be clearer to make this a reference so that we are immediately aware it's not a pointer to an array of filters?
| uint16_t filter_count; ///< Number of category filters. | ||
| uint8_t type; ///< Handler type (a value defined by the `log_handler_type` enum). | ||
| uint8_t level; ///< Default logging level (a value defined by the `LogLevel` enum). | ||
| } __attribute__((aligned(4))) log_handler; |
There was a problem hiding this comment.
Bravo. If the struct has to adhere to a very specific layout for external compliance, it might be a good idea to add some static macros asserting the layout is as expected.
There was a problem hiding this comment.
There's no requirement for specific alignment. This API uses C-style inheritance and aligning base structures to a 4-byte boundary helps to define predictable layout in derived structures
| virtual LogHandler* createHandler(const char *type, LogLevel level, LogCategoryFilters filters, Print *stream, | ||
| const JSONValue ¶ms) = 0; // TODO: Use some generic container or a buffer instead of JSONValue | ||
| virtual void destroyHandler(LogHandler *handler); | ||
| virtual LogHandler* createHandler(log_handler_type type, LogLevel level, LogCategoryFilters filters, Print* stream = nullptr) = 0; |
There was a problem hiding this comment.
This looks like an API change - can you clarify please how this is a safe change and doesn't break compatibility. I believe I know why, but don't want to presume!
There was a problem hiding this comment.
It's technically a breaking change, however, the API was marked as experimental in the code and was never documented: spark_wiring_logging.h#L449 (develop)
| r->level = (LogLevel)cmd->handler->level; | ||
| if (cmd->stream) { | ||
| r->streamType = (log_stream_type)cmd->stream->type; | ||
| if (isSerialStreamType(r->streamType)) { |
There was a problem hiding this comment.
Should determination of serial streams be moved down to the main API? Seems like it should live closer to the stream type definitions.
| const auto r = (Result*)data; | ||
| Handler h = {}; | ||
| h.handlerId = id; | ||
| if (!h.handlerId) { |
There was a problem hiding this comment.
CHECK_TRUE() returns an error code while this callback is expected to return bool
| #if PLATFORM_ID != 3 | ||
| if (stream == &Serial) { | ||
| Serial.end(); | ||
| // FIXME: Uninitializing the primary USB serial detaches a Gen 3 device from the host |
There was a problem hiding this comment.
Given it's a Gen3 issue, should we make it platform conditional?
…erent error code to notify the client that the logging feature is disabled
a654b5d to
2a2b8e0
Compare
Changelog
FEATURE_CONFIGURABLE_LOGGINGtoFEATURE_LOG_CONFIG.Serialin listening mode.Problem
This PR reimplements the control requests for runtime logging configuration using protobuf (the original implementation used JSON).
The most part of the logging framework is implemented in the user module. In order to reduce the overhead for user applications, parsing of protobuf messages is performed in the system module. A deserialized configuration is then passed to the user module via a thin system API layer (see
system_logging.h).Note that the capability to configure logging at runtime is disabled by default. The application needs to set a feature flag in order to enable it (
FEATURE_LOG_CONFIG). Unfortunately, we can't enable this feature by default and provide an option to disable it, because in that case the linker won't be able to optimize the unused code out. A solution would be to move the logging framework to the system module entirely.Steps to Test
particle-usblibrary:test.js:particle-usb:./test.js addand verify that you can see the device's logging output on theSerialandSerial1interfaces:Run
./test.js listand verify that the command showslogger_1andlogger_2in the list of active log handlers.Run
./test.js removeand verify that the device has stopped to generate log messages.Run
./test.js listand verify that the list of active log handlers is empty.References