-
Notifications
You must be signed in to change notification settings - Fork 518
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Runtime logging configuration #1748
base: develop
Are you sure you want to change the base?
Conversation
1d8cca4
to
8d12d4b
Compare
1259cae
to
36fb798
Compare
system/src/control/diagnostics.h
Outdated
|
||
namespace control { | ||
|
||
namespace diagnostics { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The diagnostics namespace seems a little strange..can you add a comment about the reasoning behind the naming?
system/src/system_logging.cpp
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
system/src/control/diagnostics.cpp
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
system/src/control/diagnostics.cpp
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CHECK_TRUE
macro?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CHECK_TRUE()
returns an error code while this callback is expected to return bool
@@ -629,7 +568,8 @@ Print* spark::DefaultOutputStreamFactory::createStream(const char *type, const J | |||
void spark::DefaultOutputStreamFactory::destroyStream(Print *stream) { | |||
#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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given it's a Gen3 issue, should we make it platform conditional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
…erent error code to notify the client that the logging feature is disabled
a654b5d
to
2a2b8e0
Compare
Changelog
FEATURE_CONFIGURABLE_LOGGING
toFEATURE_LOG_CONFIG
.Serial
in 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-usb
library:test.js
:particle-usb
:./test.js add
and verify that you can see the device's logging output on theSerial
andSerial1
interfaces:Run
./test.js list
and verify that the command showslogger_1
andlogger_2
in the list of active log handlers.Run
./test.js remove
and verify that the device has stopped to generate log messages.Run
./test.js list
and verify that the list of active log handlers is empty.References