-
Notifications
You must be signed in to change notification settings - Fork 440
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
Update logs sdk and api to follow specification #1884
Conversation
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## main #1884 +/- ##
=======================================
Coverage 87.12% 87.12%
=======================================
Files 165 165
Lines 4596 4596
=======================================
Hits 4004 4004
Misses 592 592
|
55ed2ef
to
41da3ac
Compare
Signed-off-by: WenTao Ou <admin@owent.net>
Signed-off-by: WenTao Ou <admin@owent.net>
Signed-off-by: WenTao Ou <admin@owent.net>
Signed-off-by: owent <admin@owent.net>
41da3ac
to
7c1ec27
Compare
Sorry for delay on this. Will provide my comments in this week. |
Thanks, should we mark the old |
@owent - Do you think this issue - open-telemetry/opentelemetry-specification#3086 - will bring any changes in the Event API/SDK implementation ? |
I thought Logger::Log() API provides single line convenience API to instrumentation libraries for emitting logs, and we should keep them as it is. |
Not yet. This PR implement the main branch of https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/event-api.md by now.And the EventLogger is a standalone component. |
OK, we can keep |
Signed-off-by: owent <admin@owent.net>
* @return nostd::span<const std::pair<nostd::string_view, common::AttributeValue>> | ||
*/ | ||
inline static nostd::span<const std::pair<nostd::string_view, common::AttributeValue>> | ||
MakeAttributes(std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>> |
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.
Won't this will have usage inconsistency across Trace and Logs. In Trace API, we can pass initializer_list directly as argument (due to use of overloaded methods), and in logs we have to use MakeAttributes() to convert and pass ?
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.
initializer_list can not be detected by universial reference(ArgumentType &&
).Is there any better suggestion 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.
What if we remove the variadic template argument from EmitLogRecord() and EmitEvent(), and have a method in LogRecord to add attributes?
LogRecord::SetAttribute(nostd::string_view key, const opentelemetry::common::AttributeValue &value) LogRecord::SetAttributes(const common::KeyValueIterable &attributes)
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.
LogRecord
already has SetAttribute
. I think it's easier to use for users if they do not need to emit log in just one call. Just like Logger::Log
, users don't need CreateLogRecord()
and then SetAttribute()
.
MakeAttributes
can be used to set attributes easier.
logger->EmitLogRecord(Severity::kFatal, "Logging an initializer list",
Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}}));
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 explanation. For logger API, we will now have two different methods doing similar thing:
logger->Log(Severity::kFatal, "Logging an initializer list", {{"key1", "value 1"}, {"key2", 2}})
And
logger->EmitLogRecord(Severity::kFatal, "Logging an initializer list",
Logger::MakeAttributes({{"key1", "value 1"}, {"key2", 2}}));
And the existing (first) one is much simpler. Or did you planned to remove the Logger::Log() method after adding the new method ?
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 have the same question above( #1884 (comment)_ ). I think we can discuss if we should keep Logger::Log
.
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 also don't see advantage having both the methods. We can get rid of Logger::Log
. Thanks for clarifying.
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, Logger::Log
is removed now.
…everity>`. Signed-off-by: WenTao Ou <admin@owent.net>
Signed-off-by: WenTao Ou <admin@owent.net>
Signed-off-by: WenTao Ou <admin@owent.net>
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.
LGTM Thanks.
Signed-off-by: WenTao Ou <admin@owent.net>
Thanks @owent for fixing all the comments. This PR was discussed in today's community meeting. As we are using variadic templates/pack-paraments, and other meta-programming concepts in the code, there was interest for other community members to have a look into the PR. The suggestion was to keep this PR open for review till next community meeting (i.e, 30th Jan) for sufficient time for others to review and comment if required :) |
Thanks. |
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.
Ok with the coding patterns used.
template <class... ArgumentType> | ||
void EmitEvent(nostd::string_view event_name, ArgumentType &&... args) | ||
{ | ||
nostd::shared_ptr<Logger> delegate_logger = GetDelegateLogger(); | ||
if (!delegate_logger) | ||
{ | ||
return; | ||
} | ||
nostd::unique_ptr<LogRecord> log_record = delegate_logger->CreateLogRecord(); | ||
if (!log_record) | ||
{ | ||
return; | ||
} | ||
|
||
IgnoreTraitResult( | ||
detail::LogRecordSetterTrait<typename std::decay<ArgumentType>::type>::template Set( | ||
log_record.get(), std::forward<ArgumentType>(args))...); | ||
|
||
EmitEvent(event_name, std::move(log_record)); | ||
} |
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.
So, with the use of variadic templates, type traits, lamda expressions in the implementation, etc ... there is a considerable complexity here.
Because this is in the public API, users trying to figure out how to use this might have some questions and will need a clear documentation in opentelemetry.io
with examples, and I include myself in "users" here.
This also increases complexity for maintenance, because if this breaks, understanding all the details and providing a fix will take more time, compared to more trivial C++ code.
I assume that the complexity here also saves from some repetitive code that would be also hard to maintain otherwise, so there are plus sides as well.
Overall, the complexity argument does not make the code invalid, so I view it as:
- subjective (people with different experiences with these patterns will have different views)
- and not objective (a given area in the code is technically broken and needs a fix)
To confirm, ok with me to have this code merged to main, knowing fully that I would need to improve my own variadic template skills as a pre requisite if I ever have to make changes here.
LGTM for this part, did not check everything else yet.
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 your feedback. Here is my thinking about this complexity.There is a little different between trace and log APIs, with trace, we always need a variable to hold the lifetime of span(Span or Scope) and decide when to call End()
by RAII, so we can set data field of Span
one by by one after we create the span.
But in the use case of logs, it's easier for users(I'm also a user of both log and trace.) to use by call just one function, this function is Logger::Log()
before and Logger::EmitLogRecord()
now.There are also many data fields we need set to LogRecord
, log body, trace information, attributes, timestamp and so on.There are three ways to set attributes before(By const T&
, std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>>
, const common::KeyValueIterable &
), and user also can decide whether to set other data fields, log body or trace information. Just consider log body, trace context and attributes, there will be more than 2*2*3+2*2=16
possibilities.Actually, we had more than 10 overloads of Logger::Log()
before.If we have more options for logs, then the overloads will increase exponentially(I'm trying to add TraceContext now, according to https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/api.md#logrecord).It will also be hard to maintain these overloads, especially we may add more options in the future.
I think we can disscuss more deeply if there is any better idea about how to solve this problem.
The approach of this PR try to use template <class ValueType> struct LogRecordSetterTrait;
to implement these overloads by type, and also ignore the argument order.We can use std::decay<ArgumentType>::type
to remove const
, reference
and violate
of ArgumentType
and use it as the template argument of template <class ValueType>
, so we can implement any overload action by just write one template specialization for LogRecordSetterTrait
. And the template <class ArgumentType> inline static LogRecord *Set(LogRecord *log_record, ArgumentType &&arg) noexcept
use the universal reference so it can accept both left value reference and right value with or without const
or violate
.
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 @owent for the details.
This seems the best solution then ... and great work.
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.
LGTM
Thanks for the great work :)
I agree that, maintaining this will be challenging but I see no better option.
Fixes #1692
Fixes #1693
Fixes #1687
Fixes #1688
Changes
include_trace_context
and scope attribute for logs API and SDK.EventLoggerProvider
andLoggerProvider
For significant contributions please make sure you have completed the following items:
CHANGELOG.md
updated for non-trivial changes