2019-02-03 09:57:12 +00:00
|
|
|
#include "TraceCollector.h"
|
2019-02-09 21:40:10 +00:00
|
|
|
|
2019-07-05 13:48:47 +00:00
|
|
|
#include <Core/Field.h>
|
|
|
|
#include <Poco/Logger.h>
|
2019-07-10 20:47:39 +00:00
|
|
|
#include <common/Pipe.h>
|
2019-07-04 22:13:51 +00:00
|
|
|
#include <common/StackTrace.h>
|
2019-02-03 09:57:12 +00:00
|
|
|
#include <common/logger_useful.h>
|
|
|
|
#include <IO/ReadHelpers.h>
|
2019-02-09 21:40:10 +00:00
|
|
|
#include <IO/ReadBufferFromFileDescriptor.h>
|
2019-07-10 20:47:39 +00:00
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
#include <IO/WriteBufferFromFileDescriptor.h>
|
2019-02-09 21:40:10 +00:00
|
|
|
#include <Common/Exception.h>
|
2019-03-04 13:03:32 +00:00
|
|
|
#include <Interpreters/TraceLog.h>
|
2019-02-03 21:30:45 +00:00
|
|
|
|
2019-07-10 20:47:39 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
LazyPipe trace_pipe;
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int NULL_POINTER_DEREFERENCE;
|
|
|
|
extern const int THREAD_IS_NOT_JOINABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
TraceCollector::TraceCollector(std::shared_ptr<TraceLog> & trace_log)
|
|
|
|
: log(&Poco::Logger::get("TraceCollector"))
|
|
|
|
, trace_log(trace_log)
|
|
|
|
{
|
|
|
|
if (trace_log == nullptr)
|
|
|
|
throw Exception("Invalid trace log pointer passed", ErrorCodes::NULL_POINTER_DEREFERENCE);
|
|
|
|
|
|
|
|
trace_pipe.open();
|
|
|
|
thread = ThreadFromGlobalPool(&TraceCollector::run, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
TraceCollector::~TraceCollector()
|
|
|
|
{
|
|
|
|
if (!thread.joinable())
|
|
|
|
LOG_ERROR(log, "TraceCollector thread is malformed and cannot be joined");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TraceCollector::notifyToStop();
|
|
|
|
thread.join();
|
|
|
|
}
|
|
|
|
|
|
|
|
trace_pipe.close();
|
|
|
|
}
|
2019-02-03 09:57:12 +00:00
|
|
|
|
2019-07-05 13:48:47 +00:00
|
|
|
/**
|
|
|
|
* Sends TraceCollector stop message
|
|
|
|
*
|
|
|
|
* Each sequence of data for TraceCollector thread starts with a boolean flag.
|
|
|
|
* If this flag is true, TraceCollector must stop reading trace_pipe and exit.
|
|
|
|
* This function sends flag with a true value to stop TraceCollector gracefully.
|
|
|
|
*
|
|
|
|
* NOTE: TraceCollector will NOT stop immediately as there may be some data left in the pipe
|
|
|
|
* before stop message.
|
|
|
|
*/
|
2019-07-10 20:47:39 +00:00
|
|
|
void TraceCollector::notifyToStop()
|
2019-07-05 13:48:47 +00:00
|
|
|
{
|
|
|
|
WriteBufferFromFileDescriptor out(trace_pipe.fds_rw[1]);
|
2019-07-10 20:47:39 +00:00
|
|
|
writeChar(true, out);
|
2019-07-05 13:48:47 +00:00
|
|
|
out.next();
|
|
|
|
}
|
2019-02-03 09:57:12 +00:00
|
|
|
|
2019-07-05 13:48:47 +00:00
|
|
|
void TraceCollector::run()
|
|
|
|
{
|
|
|
|
ReadBufferFromFileDescriptor in(trace_pipe.fds_rw[0]);
|
2019-05-19 20:22:44 +00:00
|
|
|
|
2019-07-05 13:48:47 +00:00
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
char is_last;
|
|
|
|
readChar(is_last, in);
|
|
|
|
if (is_last)
|
|
|
|
break;
|
2019-05-19 20:22:44 +00:00
|
|
|
|
2019-07-05 13:48:47 +00:00
|
|
|
std::string query_id;
|
|
|
|
StackTrace stack_trace(NoCapture{});
|
|
|
|
TimerType timer_type;
|
2019-02-09 21:40:10 +00:00
|
|
|
|
2019-07-05 13:48:47 +00:00
|
|
|
readStringBinary(query_id, in);
|
|
|
|
readPODBinary(stack_trace, in);
|
|
|
|
readPODBinary(timer_type, in);
|
2019-02-03 21:30:45 +00:00
|
|
|
|
2019-07-05 13:48:47 +00:00
|
|
|
const auto size = stack_trace.getSize();
|
2019-07-10 20:47:39 +00:00
|
|
|
const auto & frames = stack_trace.getFrames();
|
2019-05-14 22:15:23 +00:00
|
|
|
|
2019-07-05 13:48:47 +00:00
|
|
|
Array trace;
|
|
|
|
trace.reserve(size);
|
|
|
|
for (size_t i = 0; i < size; i++)
|
|
|
|
trace.emplace_back(UInt64(reinterpret_cast<uintptr_t>(frames[i])));
|
2019-02-03 21:30:45 +00:00
|
|
|
|
2019-07-05 13:48:47 +00:00
|
|
|
TraceLogElement element{std::time(nullptr), timer_type, query_id, trace};
|
2019-02-03 21:30:45 +00:00
|
|
|
|
2019-07-05 13:48:47 +00:00
|
|
|
trace_log->add(element);
|
2019-02-03 09:57:12 +00:00
|
|
|
}
|
|
|
|
}
|
2019-07-10 20:47:39 +00:00
|
|
|
|
|
|
|
}
|