Skip to content

Commit

Permalink
[EXPORTER] Refactor ElasticSearchRecordable (#3164)
Browse files Browse the repository at this point in the history
  • Loading branch information
sjinks authored Dec 2, 2024
1 parent f167c36 commit ac4bba7
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 155 deletions.
2 changes: 1 addition & 1 deletion exporters/elasticsearch/src/es_log_record_exporter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class ResponseHandler : public http_client::EventHandler
{
log_message = BuildResponseLogMessage(response, body_);

OTEL_INTERNAL_LOG_ERROR("ES Log Exporter] Export failed, " << log_message);
OTEL_INTERNAL_LOG_ERROR("[ES Log Exporter] Export failed, " << log_message);
}

if (console_debug_)
Expand Down
193 changes: 39 additions & 154 deletions exporters/elasticsearch/src/es_log_recordable.cc
Original file line number Diff line number Diff line change
@@ -1,14 +1,41 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include <chrono>
#include <ctime>
#include <nlohmann/json.hpp>
#include <string>

#include "opentelemetry/exporters/elasticsearch/es_log_recordable.h"
#include "opentelemetry/logs/severity.h"
#include "opentelemetry/nostd/variant.h"
#include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/trace/span_id.h"
#include "opentelemetry/trace/trace_flags.h"
#include "opentelemetry/trace/trace_id.h"

namespace nlohmann
{
template <>
struct adl_serializer<opentelemetry::sdk::common::OwnedAttributeValue>
{
static void to_json(json &j, const opentelemetry::sdk::common::OwnedAttributeValue &v)
{
opentelemetry::nostd::visit([&j](const auto &value) { j = value; }, v);
}
};

template <>
struct adl_serializer<opentelemetry::common::AttributeValue>
{
static void to_json(json &j, const opentelemetry::common::AttributeValue &v)
{
opentelemetry::nostd::visit([&j](const auto &value) { j = value; }, v);
}
};
} // namespace nlohmann

OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
Expand All @@ -18,146 +45,13 @@ void ElasticSearchRecordable::WriteValue(
const opentelemetry::sdk::common::OwnedAttributeValue &value,
const std::string &name)
{
namespace common = opentelemetry::sdk::common;
switch (value.index())
{
case common::kTypeBool:
json_[name] = opentelemetry::nostd::get<bool>(value) ? true : false;
return;
case common::kTypeInt:
json_[name] = opentelemetry::nostd::get<int>(value);
return;
case common::kTypeInt64:
json_[name] = opentelemetry::nostd::get<int64_t>(value);
return;
case common::kTypeUInt:
json_[name] = opentelemetry::nostd::get<unsigned int>(value);
return;
case common::kTypeUInt64:
json_[name] = opentelemetry::nostd::get<uint64_t>(value);
return;
case common::kTypeDouble:
json_[name] = opentelemetry::nostd::get<double>(value);
return;
case common::kTypeString:
json_[name] = opentelemetry::nostd::get<std::string>(value).data();
return;
default:
return;
}
json_[name] = value;
}

void ElasticSearchRecordable::WriteValue(const opentelemetry::common::AttributeValue &value,
const std::string &name)
{

// Assert size of variant to ensure that this method gets updated if the variant
// definition changes

if (nostd::holds_alternative<bool>(value))
{
json_[name] = opentelemetry::nostd::get<bool>(value) ? true : false;
}
else if (nostd::holds_alternative<int>(value))
{
json_[name] = opentelemetry::nostd::get<int>(value);
}
else if (nostd::holds_alternative<int64_t>(value))
{
json_[name] = opentelemetry::nostd::get<int64_t>(value);
}
else if (nostd::holds_alternative<unsigned int>(value))
{
json_[name] = opentelemetry::nostd::get<unsigned int>(value);
}
else if (nostd::holds_alternative<uint64_t>(value))
{
json_[name] = opentelemetry::nostd::get<uint64_t>(value);
}
else if (nostd::holds_alternative<double>(value))
{
json_[name] = opentelemetry::nostd::get<double>(value);
}
else if (nostd::holds_alternative<const char *>(value))
{
json_[name] = std::string(nostd::get<const char *>(value));
}
else if (nostd::holds_alternative<nostd::string_view>(value))
{
json_[name] = static_cast<std::string>(opentelemetry::nostd::get<nostd::string_view>(value));
}
else if (nostd::holds_alternative<nostd::span<const uint8_t>>(value))
{
nlohmann::json array_value = nlohmann::json::array();
for (const auto &val : nostd::get<nostd::span<const uint8_t>>(value))
{
array_value.push_back(val);
}
json_[name] = array_value;
}
else if (nostd::holds_alternative<nostd::span<const bool>>(value))
{
nlohmann::json array_value = nlohmann::json::array();
for (const auto &val : nostd::get<nostd::span<const bool>>(value))
{
array_value.push_back(val);
}
json_[name] = array_value;
}
else if (nostd::holds_alternative<nostd::span<const int>>(value))
{
nlohmann::json array_value = nlohmann::json::array();
for (const auto &val : nostd::get<nostd::span<const int>>(value))
{
array_value.push_back(val);
}
json_[name] = array_value;
}
else if (nostd::holds_alternative<nostd::span<const int64_t>>(value))
{
nlohmann::json array_value = nlohmann::json::array();
for (const auto &val : nostd::get<nostd::span<const int64_t>>(value))
{
array_value.push_back(val);
}
json_[name] = array_value;
}
else if (nostd::holds_alternative<nostd::span<const unsigned int>>(value))
{
nlohmann::json array_value = nlohmann::json::array();
for (const auto &val : nostd::get<nostd::span<const unsigned int>>(value))
{
array_value.push_back(val);
}
json_[name] = array_value;
}
else if (nostd::holds_alternative<nostd::span<const uint64_t>>(value))
{
nlohmann::json array_value = nlohmann::json::array();
for (const auto &val : nostd::get<nostd::span<const uint64_t>>(value))
{
array_value.push_back(val);
}
json_[name] = array_value;
}
else if (nostd::holds_alternative<nostd::span<const double>>(value))
{
nlohmann::json array_value = nlohmann::json::array();
for (const auto &val : nostd::get<nostd::span<const double>>(value))
{
array_value.push_back(val);
}
json_[name] = array_value;
}
else if (nostd::holds_alternative<nostd::span<const nostd::string_view>>(value))
{
nlohmann::json array_value = nlohmann::json::array();
for (const auto &val : nostd::get<nostd::span<const nostd::string_view>>(value))
{
array_value.push_back(static_cast<std::string>(val));
}
json_[name] = array_value;
}
json_[name] = value;
}

ElasticSearchRecordable::ElasticSearchRecordable() noexcept : sdk::logs::Recordable()
Expand All @@ -180,27 +74,19 @@ void ElasticSearchRecordable::SetTimestamp(
#if __cplusplus >= 202002L
const std::string dateStr = std::format("{:%FT%T%Ez}", timePoint);
#else
const static int dateToSecondsSize = 19;
const static int millisecondsSize = 8;
const static int timeZoneSize = 1;
const static int dateSize = dateToSecondsSize + millisecondsSize + timeZoneSize;

std::time_t time = std::chrono::system_clock::to_time_t(timePoint);
std::tm tm = *std::gmtime(&time);

char bufferDate[dateSize]; // example: 2024-10-18T07:26:00.123456Z
std::strftime(bufferDate, sizeof(bufferDate), "%Y-%m-%dT%H:%M:%S", &tm);
auto microseconds =
std::chrono::duration_cast<std::chrono::microseconds>(timePoint.time_since_epoch()) %
std::chrono::seconds(1);

char bufferMilliseconds[millisecondsSize];
std::snprintf(bufferMilliseconds, sizeof(bufferMilliseconds), ".%06ld",
// `sizeof()` includes the null terminator
constexpr auto dateSize = sizeof("YYYY-MM-DDTHH:MM:SS.uuuuuuZ");
char bufferDate[dateSize];
auto offset = std::strftime(bufferDate, sizeof(bufferDate), "%Y-%m-%dT%H:%M:%S", &tm);
std::snprintf(bufferDate + offset, sizeof(bufferDate) - offset, ".%06ldZ",
static_cast<long>(microseconds.count()));

std::strcat(bufferDate, bufferMilliseconds);
std::strcat(bufferDate, "Z");

const std::string dateStr(bufferDate);
#endif

Expand All @@ -221,9 +107,8 @@ void ElasticSearchRecordable::SetSeverity(opentelemetry::logs::Severity severity
std::uint32_t severity_index = static_cast<std::uint32_t>(severity);
if (severity_index >= std::extent<decltype(opentelemetry::logs::SeverityNumToText)>::value)
{
std::stringstream sout;
sout << "Invalid severity(" << severity_index << ")";
severityField = sout.str();
severityField =
std::string("Invalid severity(").append(std::to_string(severity_index)).append(")");
}
else
{
Expand All @@ -240,7 +125,7 @@ void ElasticSearchRecordable::SetTraceId(const opentelemetry::trace::TraceId &tr
{
if (trace_id.IsValid())
{
char trace_buf[32];
char trace_buf[opentelemetry::trace::TraceId::kSize * 2];
trace_id.ToLowerBase16(trace_buf);
json_["traceid"] = std::string(trace_buf, sizeof(trace_buf));
}
Expand All @@ -254,7 +139,7 @@ void ElasticSearchRecordable::SetSpanId(const opentelemetry::trace::SpanId &span
{
if (span_id.IsValid())
{
char span_buf[16];
char span_buf[opentelemetry::trace::SpanId::kSize * 2];
span_id.ToLowerBase16(span_buf);
json_["spanid"] = std::string(span_buf, sizeof(span_buf));
}
Expand Down Expand Up @@ -282,7 +167,7 @@ void ElasticSearchRecordable::SetAttribute(
void ElasticSearchRecordable::SetResource(
const opentelemetry::sdk::resource::Resource &resource) noexcept
{
for (auto &attribute : resource.GetAttributes())
for (const auto &attribute : resource.GetAttributes())
{
WriteValue(attribute.second, attribute.first);
}
Expand Down

2 comments on commit ac4bba7

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'OpenTelemetry-cpp api Benchmark'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: ac4bba7 Previous: f167c36 Ratio
BM_SpinLockThrashing/1/process_time/real_time 1.7704296112060547 ms/iter 0.14020299911499023 ms/iter 12.63

This comment was automatically generated by workflow using github-action-benchmark.

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'OpenTelemetry-cpp sdk Benchmark'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: ac4bba7 Previous: f167c36 Ratio
BM_BaselineBuffer/1 9229660.034179688 ns/iter 1953257.5607299805 ns/iter 4.73
BM_BaselineBuffer/2 16163244.247436523 ns/iter 6612408.16116333 ns/iter 2.44

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.