2020-10-22 16:47:20 +00:00
|
|
|
#include "OpenTelemetrySpanLog.h"
|
2020-08-20 20:59:40 +00:00
|
|
|
|
|
|
|
#include <DataTypes/DataTypeArray.h>
|
|
|
|
#include <DataTypes/DataTypeDate.h>
|
|
|
|
#include <DataTypes/DataTypeDateTime.h>
|
2020-09-30 16:16:33 +00:00
|
|
|
#include <DataTypes/DataTypeDateTime64.h>
|
2020-08-20 20:59:40 +00:00
|
|
|
#include <DataTypes/DataTypesNumber.h>
|
|
|
|
#include <DataTypes/DataTypeString.h>
|
|
|
|
#include <DataTypes/DataTypeUUID.h>
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
Block OpenTelemetrySpanLogElement::createBlock()
|
|
|
|
{
|
|
|
|
return {
|
|
|
|
{std::make_shared<DataTypeUUID>(), "trace_id"},
|
|
|
|
{std::make_shared<DataTypeUInt64>(), "span_id"},
|
|
|
|
{std::make_shared<DataTypeUInt64>(), "parent_span_id"},
|
|
|
|
{std::make_shared<DataTypeString>(), "operation_name"},
|
2020-09-30 16:16:33 +00:00
|
|
|
{std::make_shared<DataTypeDateTime64>(6), "start_time_us"},
|
|
|
|
{std::make_shared<DataTypeDateTime64>(6), "finish_time_us"},
|
2020-09-08 13:19:27 +00:00
|
|
|
{std::make_shared<DataTypeDate>(), "finish_date"},
|
2020-08-20 20:59:40 +00:00
|
|
|
{std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>()),
|
|
|
|
"attribute.names"},
|
|
|
|
{std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>()),
|
|
|
|
"attribute.values"}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenTelemetrySpanLogElement::appendToBlock(MutableColumns & columns) const
|
|
|
|
{
|
|
|
|
size_t i = 0;
|
|
|
|
|
2020-08-27 18:44:20 +00:00
|
|
|
columns[i++]->insert(UInt128(Int128(trace_id)));
|
2020-08-20 20:59:40 +00:00
|
|
|
columns[i++]->insert(span_id);
|
|
|
|
columns[i++]->insert(parent_span_id);
|
|
|
|
columns[i++]->insert(operation_name);
|
2020-09-30 16:16:33 +00:00
|
|
|
columns[i++]->insert(start_time_us);
|
|
|
|
columns[i++]->insert(finish_time_us);
|
|
|
|
columns[i++]->insert(DateLUT::instance().toDayNum(finish_time_us / 1000000));
|
2020-08-20 20:59:40 +00:00
|
|
|
columns[i++]->insert(attribute_names);
|
2020-11-10 05:50:32 +00:00
|
|
|
// The user might add some ints values, and we will have Int Field, and the
|
|
|
|
// insert will fail because the column requires Strings. Convert the fields
|
|
|
|
// here, because it's hard to remember to convert them in all other places.
|
|
|
|
Array string_values;
|
|
|
|
string_values.reserve(attribute_values.size());
|
|
|
|
for (auto & value : attribute_values)
|
|
|
|
{
|
|
|
|
string_values.push_back(toString(value));
|
|
|
|
}
|
|
|
|
columns[i++]->insert(string_values);
|
2020-08-20 20:59:40 +00:00
|
|
|
}
|
|
|
|
|
2020-11-09 15:07:38 +00:00
|
|
|
OpenTelemetrySpanHolder::OpenTelemetrySpanHolder(const std::string & _operation_name)
|
|
|
|
{
|
|
|
|
auto & thread = CurrentThread::get();
|
|
|
|
|
|
|
|
trace_id = thread.opentelemetry_trace_id;
|
|
|
|
if (!trace_id)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
parent_span_id = thread.opentelemetry_current_span_id;
|
|
|
|
span_id = thread_local_rng();
|
|
|
|
operation_name = _operation_name;
|
|
|
|
start_time_us = std::chrono::duration_cast<std::chrono::microseconds>(
|
|
|
|
std::chrono::system_clock::now().time_since_epoch()).count();
|
|
|
|
|
2020-11-10 05:50:32 +00:00
|
|
|
// ****** remove this
|
|
|
|
attribute_names.push_back("clickhouse.start.stacktrace");
|
2020-11-09 15:07:38 +00:00
|
|
|
attribute_values.push_back(StackTrace().toString());
|
|
|
|
|
|
|
|
thread.opentelemetry_current_span_id = span_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
OpenTelemetrySpanHolder::~OpenTelemetrySpanHolder()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (!trace_id)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// First of all, return old value of current span.
|
|
|
|
auto & thread = CurrentThread::get();
|
|
|
|
assert(thread.opentelemetry_current_span_id = span_id);
|
|
|
|
thread.opentelemetry_current_span_id = parent_span_id;
|
|
|
|
|
|
|
|
// Not sure what's the best way to access the log from here.
|
|
|
|
auto * thread_group = CurrentThread::getGroup().get();
|
|
|
|
// Not sure whether and when this can be null.
|
|
|
|
if (!thread_group)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto * context = thread_group->query_context;
|
|
|
|
if (!context)
|
|
|
|
{
|
|
|
|
// Both global and query contexts can be null when executing a
|
|
|
|
// background task, and global context can be null for some
|
|
|
|
// queries.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//******** remove this
|
|
|
|
attribute_names.push_back("clickhouse.query_id");
|
|
|
|
attribute_values.push_back(context->getCurrentQueryId());
|
2020-11-10 05:50:32 +00:00
|
|
|
attribute_names.push_back("clickhouse.end.stacktrace");
|
|
|
|
attribute_values.push_back(StackTrace().toString());
|
2020-11-09 15:07:38 +00:00
|
|
|
|
|
|
|
auto log = context->getOpenTelemetrySpanLog();
|
|
|
|
if (!log)
|
|
|
|
{
|
|
|
|
// The log might be disabled.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
finish_time_us = std::chrono::duration_cast<std::chrono::microseconds>(
|
|
|
|
std::chrono::system_clock::now().time_since_epoch()).count();
|
|
|
|
|
|
|
|
// We should use a high resolution monotonic clock for calculating
|
|
|
|
// duration, but this way will do for now.
|
|
|
|
duration_ns = (finish_time_us - start_time_us) * 1000;
|
|
|
|
|
|
|
|
|
|
|
|
log->add(OpenTelemetrySpanLogElement(
|
|
|
|
static_cast<OpenTelemetrySpan>(*this)));
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
tryLogCurrentException(__FUNCTION__);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-20 20:59:40 +00:00
|
|
|
}
|
|
|
|
|