Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
[API] Add user facing Logging API and Benchmarks #2094
[API] Add user facing Logging API and Benchmarks #2094
Changes from 1 commit
60fb322
a613863
4f6b360
9c5080b
6ab98fe
ca51896
d2a1a45
fc92d60
c6e2296
8e82391
11ced70
8e9c884
b9846bf
d6e96af
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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 goes against the standard practice of not doing any memory copy at the API/SDK surface. The recordable interface design ensures that we can directly serialize the data at exporter, without creating any intermediate copies at the API/SDK level. One solution to avoid this copy operation can be to get rid of EventId class, and pass the event-id (as int64_t) and event-name (as notstd::string_view) directly to Log methods. Also we have only used primitive, or non-owning
nostd
types as API arguments. Even though we can debate that passing reference/pointer to a user created class mayn't break the ABI, in general good to avoid if we can.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.
No memory will be allocated in our logging APIs. The
EventId
class is supposed to be created by the user with sort of global lifetime, it so copies the string instead of using anystring_view
on existingstring
because it then requires the user to manage the original string object explicitly. The allocation and free of such object is not in the scope of logging API as it only takes const reference on such object.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.
Why not use
std::string name_;
here? The usage of this variable above seems just like std::string, and do not add a tail\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.
EventId
can be read from both user and SDK code, which requires it to be ABI compatible.std::string
cannot guarantee such ABI compatibility requirement across the boundary between user code/SDK so cannot be used. I'd expect there isnostd::string
but we don't have it, then switch to primitivechar
pointer wrapped innostd::unique_ptr
. Let me know if this addresses the concern.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.
Thanks for the explain, on the other hand, should we set
name_[name.length()] = 0;
here?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.
Yes, that makes sense. Set the last element of
name_
as 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.
Do we need each of these helpers to be virtual functions ?
A simple inline function seem sufficient.
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.
I am confused about the intended usage for this helper:
Is the caller supposed to check Enabled for each call, as in:
or is Trace() responsible to check the severity flag itself, as in:
The benchmarks shows both usage, is this code writing un wanted traces in the second case ?
The check for Enabled() seems missing from the code path.
Beside, if the whole point of Logger::minimum_severity_ is to check the flags in the API before making a virtual function call, then why making calls here to virtual functions Log() and EmitLogRecord() ?
Suggested changes:
For example:
Edit: If
EmitLogRecord()
is also considered user facing (it is in the spec), then:where
DoEmitLogRecord()
is a protected virtual method.This will add clarity:
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.
Thanks for the suggestion @marcalff .
If we are not going to call
Enabled()
in user facing API, then inline the call ofDoLogRecord
seems unnecessary for all the wrappers then? I don't have strong preference as the name implied they are just wrappers. But I can also revisit this part in the SDK support because changing the implementation will not break the user facing API.Please let me know if anything is missed here.
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.
Just want to have a discuss.
We have a log macro like this before in our project.
And when we use
WLOGDEBUG(logger, "Debug message: {}", protobuf_message.DebugString());
and if the debug log is not enabled,protobuf_message.DebugString()
will not be called and it's a high cost function.Is there any way we can achieve a similar effect?
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.
Perhaps we can define similar macro to help the user reduce boilerplate code, but it can avoid the logging cost. Based on the logging statement you shared, the the variable
protobuf_message
might be only need for logging, and it could do heavy initialization (like map or load string resources). This happens in the definition ofprotobuf_message
which cannot be be optimized here.While providing macros could help, the pointer in our API is make
Enabled
check explicit to the user, so they are aware of this and encouraged to do the optimization to archive high performance logging.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.
Let's continue the discussion about Enabled() in the next patch, for the SDK part.
The fact that the caller MAY use Enabled() to optimize paths that evaluate complex arguments is good.
Still we can't force that the caller MUST use Enabled() all the time, so the implementation will need to check it again at some point.