Skip to content

Commit

Permalink
HPCC-30470 Jtrace default JLog exporter
Browse files Browse the repository at this point in the history
- Provide Jlog exporter and exporterfactory
- Replaces noop exporter as default exporter
- Reports span data at span destruction time
- Reports internal OTel timing data
- Reports HPCC GUID, CallerID as attributes

Signed-off-by: Rodrigo Pastrana <[email protected]>
  • Loading branch information
rpastrana committed Nov 29, 2023
1 parent f5ef1ea commit 4e7846d
Showing 1 changed file with 232 additions and 1 deletion.
233 changes: 232 additions & 1 deletion system/jlib/jtrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "opentelemetry/sdk/trace/simple_processor_factory.h"
#include "opentelemetry/sdk/trace/batch_span_processor_factory.h"
#include "opentelemetry/exporters/ostream/span_exporter_factory.h"// auto exporter = opentelemetry::exporter::trace::OStreamSpanExporterFactory::Create();
#include "opentelemetry/exporters/ostream/common_utils.h"
//#define oldForEach ForEach // error: ‘ForEach’ was not declared in this scope
#undef ForEach //opentelemetry defines ForEach
#include "opentelemetry/exporters/memory/in_memory_span_exporter_factory.h"
Expand Down Expand Up @@ -107,6 +108,236 @@ class NoopSpanExporterFactory
}
};

/**
* Converts an OpenTelemetry span kind to its string representation.
* These are OTel span kinds defined in api/include/opentelemetry/trace/span.h,
* not HPCC JLib CSpan kinds
*
* @param spanKind The OpenTelemetry span kind to convert.
* @return The string representation of the OpenTelemetry span kind.
*/
const char * spanKindToString(opentelemetry::trace::SpanKind spanKind)
{
switch (spanKind)
{
case opentelemetry::trace::SpanKind::kClient:
return "Client";
case opentelemetry::trace::SpanKind::kServer:
return "Server";
case opentelemetry::trace::SpanKind::kProducer:
return "Producer";
case opentelemetry::trace::SpanKind::kConsumer:
return "Consumer";
case opentelemetry::trace::SpanKind::kInternal:
return "Internal";
default:
return "Unknown";
}
}

class JLogSpanExporter final : public opentelemetry::sdk::trace::SpanExporter
{
public:
JLogSpanExporter() {}

/**
* @return Returns a unique pointer to an empty recordable object
*/
std::unique_ptr<opentelemetry::sdk::trace::Recordable> MakeRecordable() noexcept override
{
return std::unique_ptr<opentelemetry::sdk::trace::Recordable>(new opentelemetry::sdk::trace::SpanData());
}

/**
* Export - Formats recordable spans in HPCC Jlog format and reports to JLog
*
* @param recordables
* @return Always returns success
*/
opentelemetry::sdk::common::ExportResult Export(
const nostd::span<std::unique_ptr<opentelemetry::sdk::trace::Recordable>> &recordables) noexcept override
{
if (isShutDown())
{
ERRLOG("JLog Trace Exporter: Export failed, exporter is shutdown");
return opentelemetry::sdk::common::ExportResult::kFailure;
}

for (auto &recordable : recordables)
{
auto span = std::unique_ptr<opentelemetry::sdk::trace::SpanData>(
static_cast<opentelemetry::sdk::trace::SpanData *>(recordable.release()));

if (span != nullptr)
{
char trace_id[32] = {0};
char span_id[16] = {0};
char parent_span_id[16] = {0};

span->GetTraceId().ToLowerBase16(trace_id);
span->GetSpanId().ToLowerBase16(span_id);
span->GetParentSpanId().ToLowerBase16(parent_span_id);

sout << "{"
<< " \"Name\": \"" << span->GetName() << "\","
<< " \"TraceId\": \"" << std::string(trace_id, 32) << "\","
<< " \"SpanId\": \"" << std::string(span_id, 16) << "\","
<< " \"kind\": \"" << spanKindToString(span->GetSpanKind()) << "\","
<< " \"ParentSpanId\": \"" << std::string(parent_span_id, 16) << "\","
<< " \"Start\": " << span->GetStartTime().time_since_epoch().count() << ","
<< " \"Duration\": " << span->GetDuration().count() << ","
<< " \"Description\": \"" << span->GetDescription() << "\","
<< " \"Status\": \"" << statusMap[int(span->GetStatus())] << "\","
<< " \"TraceState\": \"" << span->GetSpanContext().trace_state()->ToHeader() << "\","
<< " \"Attributes\": ";
printAttributes(span->GetAttributes());
sout << ",";
sout << " \"Events\": ";
printEvents(span->GetEvents());
sout << ",";
sout << " \"Links\": ";
printLinks(span->GetLinks());
sout << ",";
sout << " \"Resources\": ";
printResources(span->GetResource());
sout << ",";
sout << " \"InstrumentedLibrary\": \"";
printInstrumentationScope(span->GetInstrumentationScope());
sout << "\" }";
}
LOG(MCoperatorTrace, "TraceSpan '%s': %s", span->GetName().data() , sout.str().c_str());
sout.str("");
sout.clear();
}
return opentelemetry::sdk::common::ExportResult::kSuccess;
}

/**
* Shut down the exporter.
* @param timeout an optional timeout.
* @return return the status of the operation.
*/
virtual bool Shutdown(
std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override
{
const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock);
shutDown = true;
return true;
}

private:
bool isShutDown() const noexcept
{
const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock);
return shutDown;
}

void printAttributes(const std::unordered_map<std::string, opentelemetry::sdk::common::OwnedAttributeValue> &map)
{
sout << "{ ";
bool first = true;
for (const auto &kv : map)
{
if (!first)
sout << ",";
else
first = false;

sout << "\"" << kv.first << "\": \"";
opentelemetry::exporter::ostream_common::print_value(kv.second, sout);
sout << "\"";
}
sout << " }";
}

void printEvents(const std::vector<opentelemetry::sdk::trace::SpanDataEvent> &events)
{
sout << "{ ";
bool first = true;
for (const auto &event : events)
{
if (!first)
sout << ",";
else
first = false;

sout << "{ ";
sout << " \"Name\": " << event.GetName() << "\","
<< " \"Timestamp\": " << event.GetTimestamp().time_since_epoch().count() << "\","
<< " \"Attributes\": ";
printAttributes(event.GetAttributes());
sout << " }";
}

sout << " }";
}

void printLinks(const std::vector<opentelemetry::sdk::trace::SpanDataLink> &links)
{
bool first = true;

sout << "{ ";
for (const auto &link : links)
{
if (!first)
sout << ",";
else
first = false;

char trace_id[32] = {0};
char span_id[16] = {0};
link.GetSpanContext().trace_id().ToLowerBase16(trace_id);
link.GetSpanContext().span_id().ToLowerBase16(span_id);
sout << " {"
<< " \"TraceId\": \"" << std::string(trace_id, 32) << "\","
<< " \"SpanId\": \"" << std::string(span_id, 16) << "\","
<< " \"TraceState\": \"" << link.GetSpanContext().trace_state()->ToHeader() << "\","
<< " \"Attributes\": ";
printAttributes(link.GetAttributes());
sout << " }";
}
sout << " }";
}

void printResources(const opentelemetry::sdk::resource::Resource &resources)
{
auto attributes = resources.GetAttributes();
if (attributes.size())
printAttributes(attributes);
}

void printInstrumentationScope(
const opentelemetry::sdk::instrumentationscope::InstrumentationScope &instrumentation_scope)
{
auto version = instrumentation_scope.GetVersion();
if (version.size())
{
sout << " \"" << instrumentation_scope.GetName() << "\": ";
sout << version;
}
}

bool shutDown = false;
std::ostringstream sout;
mutable opentelemetry::common::SpinLockMutex lock;

// Mapping status number to the string from api/include/opentelemetry/trace/canonical_code.h
std::map<int, std::string> statusMap{{0, "Unset"}, {1, "Ok"}, {2, "Error"}};
};

class JLogSpanExporterFactory
{
public:
/**
* Create a NoopSpanExporter.
*/
static std::unique_ptr<opentelemetry::sdk::trace::SpanExporter> Create()
{
return std::unique_ptr<opentelemetry::sdk::trace::SpanExporter>(
new JLogSpanExporter());
}
};

class CHPCCHttpTextMapCarrier : public opentelemetry::context::propagation::TextMapCarrier
{
public:
Expand Down Expand Up @@ -943,7 +1174,7 @@ Expected Configuration format:
alwaysCreateGlobalIds : false #optional - should global ids always be created?
alwaysCreateTraceIds #optional - should trace ids always be created?
exporter: #optional - Controls how trace data is exported/reported
type: OTLP #OS|OTLP|Prometheus|HPCC (default: no export, jlog entry)
type: OTLP #OS|OTLP|Prometheus|JLog (default: no export, jlog entry)
endpoint: "localhost:4317" #exporter specific key/value pairs
useSslCredentials: true
sslCredentialsCACcert: "ssl-certificate"
Expand Down

0 comments on commit 4e7846d

Please sign in to comment.