-
Notifications
You must be signed in to change notification settings - Fork 300
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
Add span events and status #794
base: develop
Are you sure you want to change the base?
Changes from 26 commits
5900cf2
056e86a
1b9d466
d01412d
b2227f5
9dd35c2
beca706
24e8e36
7004622
57ead82
aea058c
c92d19c
84a6697
cd47c49
13b1fcf
d72491d
e27246b
b6704d5
f2d0fd8
146372d
5472f64
ef410e3
1e1c73d
a143bb5
1f61f80
715dc7e
3d7d18a
10cf365
8d796e5
0afe674
a679266
4a761bd
0959e57
6315ede
777ea21
27d80e2
ebd5001
1da9c84
5392321
86a774c
64386d7
9b00bad
84c7ac7
3c9ddfd
7896216
cb5bd17
140eac9
5114a21
a99e283
eaa9ef7
d70c85a
814b22f
9cee7c0
5046d79
4885f86
181bbf2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,36 @@ class Span final { | |
public: | ||
class Impl; | ||
|
||
/// @brief Operation status code. | ||
enum class StatusCode : uint8_t { | ||
kUnset, // Default status. | ||
kOk, // Operation has completed successfully. | ||
kError, // The operation contains an error. | ||
}; | ||
|
||
/// @brief Create span event | ||
struct Event final { | ||
/// @brief Constructor. | ||
/// @param name Event name. | ||
/// @param time_unix_nano Event timestamp. | ||
Event( | ||
const std::string_view name, | ||
nepridumalnik marked this conversation as resolved.
Show resolved
Hide resolved
|
||
double time_unix_nano = std::chrono::duration_cast<std::chrono::nanoseconds>( | ||
std::chrono::system_clock::now().time_since_epoch() | ||
) | ||
.count() | ||
); | ||
|
||
/// @brief Default constructor. | ||
Event() = default; | ||
fdr400 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// @brief Event timestamp. | ||
double time_unix_nano{}; | ||
|
||
/// @brief Event name. | ||
std::string name; | ||
fdr400 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
explicit Span( | ||
TracerPtr tracer, | ||
std::string name, | ||
|
@@ -157,6 +187,12 @@ class Span final { | |
/// @overload AddNonInheritableTag | ||
void AddNonInheritableTags(const logging::LogExtra&); | ||
|
||
/// Add an event to Span. | ||
void AddEvent(const std::string_view event_name); | ||
fdr400 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// Set span status. | ||
void SetStatus(StatusCode status, const std::string_view description); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already has method that sets error flag: It is bad to have two methods for making the same result. I think the right solution is to remove and use Maybe there is another better solution? |
||
|
||
/// @brief Sets level for tags logging | ||
void SetLogLevel(logging::Level log_level); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,6 +76,7 @@ class Span::Impl : public boost::intrusive::list_base_hook<boost::intrusive::lin | |
void AttachToCoroStack(); | ||
|
||
private: | ||
void LogEvents(logging::impl::TagWriter& writer) const; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's remove the method and do all work in DoLogOpenTracing Something like in the end of if (!events_.empty()) {
const auto events_tag = jaeger::MakeTagFromEvents(events_);
writer.PutTag(jaeger::kEvents, events_tag);
} where std::string MakeTagFromEvents(const std::vector<Span::Event>& events) {
formats::json::StringBuilder builder;
{
const formats::json::StringBuilder::ObjectGuard event_guard(builder);
for (const auto& event : events) {
builder.Key(event.name);
builder.WriteUInt64(event.time_unix_nano);
}
}
return builder.GetString();
} |
||
void LogOpenTracing() const; | ||
void DoLogOpenTracing(logging::impl::TagWriter writer) const; | ||
static void AddOpentracingTags(formats::json::StringBuilder& output, const logging::LogExtra& input); | ||
|
@@ -105,6 +106,8 @@ class Span::Impl : public boost::intrusive::list_base_hook<boost::intrusive::lin | |
const ReferenceType reference_type_; | ||
utils::impl::SourceLocation source_location_; | ||
|
||
std::vector<Span::Event> events_; | ||
|
||
friend class Span; | ||
friend class SpanBuilder; | ||
friend class TagScope; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,15 @@ LoggerComponent::LoggerComponent(const components::ComponentConfig& config, cons | |
logger_config.extra_attributes = config["extra-attributes"].As<std::unordered_map<std::string, std::string>>({}); | ||
logger_config.attributes_mapping = | ||
config["attributes-mapping"].As<std::unordered_map<std::string, std::string>>({}); | ||
|
||
// Define error mapping | ||
if (logger_config.attributes_mapping.find("otel_status_code") == logger_config.attributes_mapping.end()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use constants for |
||
logger_config.attributes_mapping["otel_status_code"] = "otel.status_code"; | ||
} | ||
if (logger_config.attributes_mapping.find("otel_status_description") == logger_config.attributes_mapping.end()) { | ||
logger_config.attributes_mapping["otel_status_description"] = "otel.status_description"; | ||
} | ||
|
||
logger_config.logs_sink = config["sinks"]["logs"].As<SinkType>(SinkType::kOtlp); | ||
logger_config.tracing_sink = config["sinks"]["tracing"].As<SinkType>(SinkType::kOtlp); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
#include <iostream> | ||
|
||
#include <userver/engine/async.hpp> | ||
#include <userver/formats/json.hpp> | ||
#include <userver/formats/parse/common_containers.hpp> | ||
#include <userver/formats/parse/to.hpp> | ||
#include <userver/logging/impl/tag_writer.hpp> | ||
|
@@ -20,11 +21,39 @@ USERVER_NAMESPACE_BEGIN | |
namespace otlp { | ||
|
||
namespace { | ||
|
||
constexpr std::string_view kTelemetrySdkLanguage = "telemetry.sdk.language"; | ||
constexpr std::string_view kTelemetrySdkName = "telemetry.sdk.name"; | ||
constexpr std::string_view kServiceName = "service.name"; | ||
|
||
const std::string kTimestampFormat = "%Y-%m-%dT%H:%M:%E*S"; | ||
|
||
std::vector<tracing::Span::Event> GetEventsFromValue(const std::string_view value) { | ||
std::vector<tracing::Span::Event> events; | ||
|
||
auto json_value = formats::json::FromString(value); | ||
nepridumalnik marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (!json_value.IsObject()) { | ||
throw std::runtime_error("Expected JSON object in \"value\""); | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can add |
||
for (const auto& [key, value] : formats::common::Items(json_value)) { | ||
events.emplace_back(key, value.As<double>()); | ||
} | ||
|
||
return events; | ||
} | ||
|
||
void WriteEventsFromValue(::opentelemetry::proto::trace::v1::Span& span, const std::string_view value) { | ||
std::vector<tracing::Span::Event> events = GetEventsFromValue(value); | ||
fdr400 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
fdr400 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for (const auto& event : events) { | ||
auto* event_proto = span.add_events(); | ||
event_proto->set_name(event.name); | ||
event_proto->set_time_unix_nano(event.time_unix_nano); | ||
} | ||
} | ||
|
||
} // namespace | ||
|
||
SinkType Parse(const yaml_config::YamlConfig& value, formats::parse::To<SinkType>) { | ||
|
@@ -92,8 +121,9 @@ void Logger::Log(logging::Level level, std::string_view msg) { | |
|
||
++stats_.by_level[static_cast<int>(level)]; | ||
|
||
[[maybe_unused]] auto parse_ok = | ||
utils::encoding::TskvReadRecord(parser, [&](std::string_view key, std::string_view value) { | ||
[[maybe_unused]] auto parse_ok = utils::encoding::TskvReadRecord( | ||
parser, | ||
[this, &log_record, ×tamp](std::string_view key, std::string_view value) { | ||
if (key == "text") { | ||
log_record.mutable_body()->set_string_value(grpc::string(std::string{value})); | ||
return true; | ||
|
@@ -119,7 +149,8 @@ void Logger::Log(logging::Level level, std::string_view msg) { | |
attributes->set_key(std::string{MapAttribute(key)}); | ||
attributes->mutable_value()->set_string_value(std::string{value}); | ||
return true; | ||
}); | ||
} | ||
); | ||
|
||
auto nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(timestamp.time_since_epoch()); | ||
log_record.set_time_unix_nano(nanoseconds.count()); | ||
|
@@ -146,8 +177,9 @@ void Logger::Trace(logging::Level level, std::string_view msg) { | |
std::string start_timestamp; | ||
std::string total_time; | ||
|
||
[[maybe_unused]] auto parse_ok = | ||
utils::encoding::TskvReadRecord(parser, [&](std::string_view key, std::string_view value) { | ||
[[maybe_unused]] auto parse_ok = utils::encoding::TskvReadRecord( | ||
nepridumalnik marked this conversation as resolved.
Show resolved
Hide resolved
|
||
parser, | ||
[this, &span, &start_timestamp, &total_time](std::string_view key, std::string_view value) { | ||
if (key == "trace_id") { | ||
span.set_trace_id(utils::encoding::FromHex(value)); | ||
return true; | ||
|
@@ -175,12 +207,24 @@ void Logger::Trace(logging::Level level, std::string_view msg) { | |
if (key == "timestamp" || key == "text") { | ||
return true; | ||
} | ||
if (key == "events") { | ||
WriteEventsFromValue(span, value); | ||
return true; | ||
} | ||
if (key == "error") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so, if error key is a special keys, maybe add assert that it is not in attributes mapping? |
||
auto attributes = span.add_attributes(); | ||
attributes->set_key(std::string{key}); | ||
attributes->mutable_value()->set_bool_value(value == "true"); | ||
|
||
return true; | ||
} | ||
|
||
auto attributes = span.add_attributes(); | ||
attributes->set_key(std::string{MapAttribute(key)}); | ||
attributes->mutable_value()->set_string_value(std::string{value}); | ||
return true; | ||
}); | ||
} | ||
); | ||
|
||
auto start_timestamp_double = std::stod(start_timestamp); | ||
span.set_start_time_unix_nano(start_timestamp_double * 1'000'000'000); | ||
|
@@ -225,7 +269,8 @@ void Logger::SendingLoop(Queue::Consumer& consumer, LogClient& log_client, Trace | |
[&scope_logs](const opentelemetry::proto::logs::v1::LogRecord& action) { | ||
auto log_records = scope_logs->add_log_records(); | ||
*log_records = action; | ||
}}, | ||
} | ||
}, | ||
action | ||
); | ||
} while (consumer.Pop(action, deadline)); | ||
|
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.