850 lines
31 KiB
C++
850 lines
31 KiB
C++
/*
|
|
* Copyright (c) 2022 OceanBase Technology Co.,Ltd.
|
|
* OceanBase is licensed under Mulan PubL v1.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v1.
|
|
* You may obtain a copy of Mulan PubL v1 at:
|
|
* http://license.coscl.org.cn/MulanPubL-1.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v1 for more details.
|
|
* ---------------------------------------------------------------------------------------
|
|
* Authors:
|
|
* Juehui <>
|
|
* ---------------------------------------------------------------------------------------
|
|
*/
|
|
#define USING_LOG_PREFIX SERVER
|
|
#include "observer/virtual_table/ob_virtual_span_info.h"
|
|
#include "observer/ob_sql_client_decorator.h"
|
|
#include "lib/oblog/ob_log_module.h"
|
|
#include "lib/trace/ob_trace.h"
|
|
#include "observer/virtual_table/ob_virtual_show_trace.h"
|
|
#include "lib/mysqlclient/ob_mysql_transaction.h"
|
|
#include "observer/ob_server_struct.h"
|
|
#include "sql/session/ob_sql_session_info.h"
|
|
|
|
using namespace oceanbase::common;
|
|
using namespace oceanbase::obmysql;
|
|
using namespace oceanbase::omt;
|
|
using namespace oceanbase::share;
|
|
namespace oceanbase {
|
|
namespace observer {
|
|
|
|
ObVirtualShowTrace::ObVirtualShowTrace() :
|
|
ObVirtualTableScannerIterator(),
|
|
ref_(),
|
|
addr_(NULL),
|
|
ipstr_(),
|
|
port_(0),
|
|
tenant_id_(common::OB_INVALID_ID),
|
|
is_first_get_(true),
|
|
is_use_index_(false),
|
|
tenant_id_array_(),
|
|
show_trace_rec_idx_(-1),
|
|
tag_buf_(NULL),
|
|
is_row_format_(true),
|
|
with_tenant_ctx_(nullptr)
|
|
{
|
|
}
|
|
|
|
ObVirtualShowTrace::~ObVirtualShowTrace() {
|
|
reset();
|
|
}
|
|
|
|
void ObVirtualShowTrace::reset()
|
|
{
|
|
ObVirtualTableScannerIterator::reset();
|
|
is_first_get_ = true;
|
|
is_use_index_ = false;
|
|
tenant_id_ = common::OB_INVALID_ID;
|
|
tenant_id_array_.reset();
|
|
addr_ = nullptr;
|
|
port_ = 0;
|
|
ipstr_.reset();
|
|
alloc_.reset();
|
|
}
|
|
|
|
int ObVirtualShowTrace::inner_open()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
// retrive span info from virtual span
|
|
SERVER_LOG(DEBUG, "tenant ids", K(effective_tenant_id_), K(tenant_id_array_));
|
|
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(set_ip(addr_))) {
|
|
SERVER_LOG(WARN, "failed to set server ip addr", K(ret));
|
|
} else {
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObVirtualShowTrace::retrive_all_span_info()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObMySQLTransaction trans;
|
|
bool with_snap_shot = true;
|
|
ObMySQLProxy *mysql_proxy = GCTX.sql_proxy_;
|
|
ObString trace_id;
|
|
if (OB_ISNULL(mysql_proxy)) {
|
|
ret = OB_NOT_INIT;
|
|
SERVER_LOG(WARN, "mysql proxy is null", K(ret));
|
|
} else if (OB_ISNULL(session_)) {
|
|
ret = OB_NOT_INIT;
|
|
SERVER_LOG(WARN, "session is null", K(ret));
|
|
} else if (OB_FAIL(trans.start(mysql_proxy, effective_tenant_id_, with_snap_shot))) {
|
|
SERVER_LOG(WARN, "failed to start transaction", K(ret), K(effective_tenant_id_));
|
|
} else {
|
|
int sql_len = 0;
|
|
is_row_format_ = session_->is_row_traceformat();
|
|
SMART_VAR(char[OB_MAX_SQL_LENGTH], sql) {
|
|
const uint64_t exec_tenant_id = effective_tenant_id_;
|
|
//const char *table_name = lib::is_oracle_mode() ? OB_ALL_VIRTUAL_TRACE_SPAN_INFO_ORA_TNAME:
|
|
// OB_ALL_VIRTUAL_TRACE_SPAN_INFO_TNAME;
|
|
const char *table_name = OB_ALL_VIRTUAL_TRACE_SPAN_INFO_TNAME;
|
|
trace_id = session_->get_last_flt_trace_id();
|
|
sql_len = snprintf(sql, OB_MAX_SQL_LENGTH,
|
|
"SELECT svr_ip, svr_port, tenant_id, trace_id, request_id, span_id, "
|
|
"parent_span_id, span_name, ref_type, start_ts, end_ts, tags, logs "
|
|
"FROM %s WHERE tenant_id = %lu AND trace_id = '%s'",
|
|
table_name,
|
|
effective_tenant_id_,
|
|
trace_id.ptr());
|
|
LOG_TRACE("send inner sql to retrive records", KP(session_), K(session_->get_proxy_sessid()),
|
|
K(session_->get_sessid()), K(table_name),
|
|
K(tenant_id_), K(trace_id_), K(trace_id),
|
|
K(effective_tenant_id_), K(ObString(sql_len, sql)));
|
|
if (sql_len >= OB_MAX_SQL_LENGTH || sql_len <= 0) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
SERVER_LOG(WARN, "failed to format sql. size not enough");
|
|
} else {
|
|
|
|
{ // make sure %res destructed before execute other sql in the same transaction
|
|
SMART_VAR(ObMySQLProxy::MySQLResult, res) {
|
|
ObMySQLResult *result = NULL;
|
|
ObISQLClient *sql_client = &trans;
|
|
uint64_t table_id = OB_ALL_VIRTUAL_TRACE_SPAN_INFO_TID;
|
|
ObSQLClientRetryWeak sql_client_retry_weak(sql_client,
|
|
exec_tenant_id,
|
|
table_id);
|
|
// retrive data from client
|
|
if (OB_FAIL(sql_client_retry_weak.read(res, exec_tenant_id, sql))) {
|
|
SERVER_LOG(WARN, "failed to read data", K(ret));
|
|
} else if (NULL == (result = res.get_result())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "failed to get result", K(ret));
|
|
} else {
|
|
while (OB_SUCC(ret) && OB_SUCC(result->next())) {
|
|
sql::ObFLTShowTraceRec* rec;
|
|
if (OB_FAIL(alloc_trace_rec(rec))) {
|
|
SERVER_LOG(WARN, "failed to alloc record", K(ret));
|
|
} else if (OB_ISNULL(rec)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null");
|
|
} else {
|
|
OZ(read_show_trace_rec_from_result(*result, *rec));
|
|
OZ(show_trace_arr_.push_back(rec));
|
|
}
|
|
}
|
|
if (OB_ITER_END == ret) {
|
|
ret = OB_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
// deep copy data
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
LOG_TRACE("after read dia log from span info", K(show_trace_arr_.count()), K(ret));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObVirtualShowTrace::read_show_trace_rec_from_result(sqlclient::ObMySQLResult &mysql_result, sql::ObFLTShowTraceRec &rec)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
char trace_id_buf[OB_MAX_SPAN_LENGTH];
|
|
char span_id_buf[OB_MAX_SPAN_LENGTH];
|
|
char parent_id_buf[OB_MAX_SPAN_LENGTH];
|
|
char span_name_buf[OB_MAX_SPAN_LENGTH];
|
|
char ipstr_buf[common::MAX_IP_ADDR_LENGTH + 2];
|
|
|
|
int64_t trace_id_len = 0;
|
|
int64_t span_id_len = 0;
|
|
int64_t parent_id_len = 0;
|
|
int64_t span_name_len = 0;
|
|
int64_t tag_len = 0;
|
|
int64_t log_len = 0;
|
|
int64_t ipstr_len = 0;
|
|
char *tag_buf = NULL;
|
|
if (OB_FAIL(get_tag_buf(tag_buf))) {
|
|
SERVER_LOG(WARN, "failed to get tag buf", K(ret));
|
|
} else {
|
|
// trace_id
|
|
EXTRACT_STRBUF_FIELD_MYSQL(mysql_result, "trace_id", trace_id_buf, OB_MAX_SPAN_LENGTH, trace_id_len);
|
|
// span_id
|
|
EXTRACT_STRBUF_FIELD_MYSQL(mysql_result, "span_id", span_id_buf, OB_MAX_SPAN_LENGTH, span_id_len);
|
|
// parent_span_id
|
|
EXTRACT_STRBUF_FIELD_MYSQL(mysql_result, "parent_span_id", parent_id_buf, OB_MAX_SPAN_LENGTH, parent_id_len);
|
|
// span_name
|
|
EXTRACT_STRBUF_FIELD_MYSQL(mysql_result, "span_name", span_name_buf, OB_MAX_SPAN_LENGTH, span_name_len);
|
|
// tenant_id
|
|
EXTRACT_INT_FIELD_MYSQL(mysql_result, "tenant_id", rec.data_.tenant_id_, int64_t);
|
|
// request_id
|
|
EXTRACT_INT_FIELD_MYSQL(mysql_result, "request_id", rec.data_.req_id_, int64_t);
|
|
// start_ts
|
|
EXTRACT_INT_FIELD_MYSQL(mysql_result, "start_ts", rec.data_.start_ts_, int64_t);
|
|
// end_ts
|
|
EXTRACT_INT_FIELD_MYSQL(mysql_result, "end_ts", rec.data_.end_ts_, int64_t);
|
|
// trace_id
|
|
EXTRACT_STRBUF_FIELD_MYSQL(mysql_result, "svr_ip", ipstr_buf, common::MAX_IP_ADDR_LENGTH + 2, ipstr_len);
|
|
// prot
|
|
EXTRACT_INT_FIELD_MYSQL(mysql_result, "svr_port", rec.port_, int64_t);
|
|
|
|
// tags
|
|
if (OB_FAIL(ret)) {
|
|
// do nothing
|
|
} else {
|
|
MEMSET(tag_buf, 0x00, OB_MAX_SPAN_TAG_LENGTH);
|
|
EXTRACT_STRBUF_FIELD_MYSQL(mysql_result, "tags", tag_buf, OB_MAX_SPAN_TAG_LENGTH, tag_len);
|
|
if (OB_FAIL(ob_write_string(alloc_, ObString(tag_len, tag_buf), rec.data_.tags_))) {
|
|
SERVER_LOG(WARN, "failed to deep copy tag", K(ret));
|
|
}
|
|
}
|
|
|
|
// logs
|
|
if (OB_FAIL(ret)) {
|
|
// do nothing
|
|
} else {
|
|
MEMSET(tag_buf, 0x00, OB_MAX_SPAN_TAG_LENGTH);
|
|
EXTRACT_STRBUF_FIELD_MYSQL(mysql_result, "logs", tag_buf, OB_MAX_SPAN_TAG_LENGTH, log_len);
|
|
if (OB_FAIL(ob_write_string(alloc_, ObString(log_len, tag_buf), rec.data_.logs_))) {
|
|
SERVER_LOG(WARN, "failed to deep copy log", K(ret));
|
|
}
|
|
}
|
|
|
|
// deep copy string
|
|
OZ (ob_write_string(alloc_, ObString(trace_id_len, trace_id_buf), rec.data_.trace_id_));
|
|
OZ (ob_write_string(alloc_, ObString(span_id_len, span_id_buf), rec.data_.span_id_));
|
|
OZ (ob_write_string(alloc_, ObString(parent_id_len, parent_id_buf), rec.data_.parent_span_id_));
|
|
OZ (ob_write_string(alloc_, ObString(span_name_len, span_name_buf), rec.data_.span_name_));
|
|
OZ (ob_write_string(alloc_, ObString(ipstr_len, ipstr_buf), rec.ipstr_));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObVirtualShowTrace::get_tag_buf(char *&tag_buf)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
char* buf = NULL;
|
|
if (NULL != tag_buf_) {
|
|
// not alloc, do nothing
|
|
} else if (NULL == (buf = (char*)alloc_.alloc(OB_MAX_SPAN_TAG_LENGTH))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
if (REACH_TIME_INTERVAL(100 * 1000)) {
|
|
SERVER_LOG(WARN, "alloc mem failed", K(OB_MAX_SPAN_TAG_LENGTH), K(ret));
|
|
}
|
|
} else {
|
|
tag_buf_ = buf;
|
|
}
|
|
tag_buf = tag_buf_;
|
|
return ret;
|
|
}
|
|
|
|
int ObVirtualShowTrace::generate_span_info_tree()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (show_trace_arr_.empty()) {
|
|
// do nothing
|
|
} else {
|
|
ObSEArray<sql::ObFLTShowTraceRec*, 16> tmp_arr;
|
|
ObSEArray<sql::ObFLTShowTraceRec*, 16> root_arr;
|
|
// find root span
|
|
bool found_root = false;
|
|
int64_t depth = 0;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < show_trace_arr_.count(); ++i) {
|
|
if (OB_ISNULL(show_trace_arr_.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null", K(i));
|
|
} else if (session_->get_last_flt_span_id().empty() &&
|
|
show_trace_arr_.at(i)->data_.parent_span_id_ == "00000000-0000-0000-0000-000000000000") {
|
|
found_root = true;
|
|
show_trace_arr_.at(i)->formatter_.level_ = depth;
|
|
OZ(root_arr.push_back(show_trace_arr_.at(i)));
|
|
} else if (!session_->get_last_flt_span_id().empty() &&
|
|
show_trace_arr_.at(i)->data_.parent_span_id_.compare(session_->get_last_flt_span_id()) == 0) {
|
|
found_root = true;
|
|
show_trace_arr_.at(i)->formatter_.level_ = depth;
|
|
OZ(root_arr.push_back(show_trace_arr_.at(i)));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
// do nothing
|
|
} else if (!found_root) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("not found root span reset show trace", K(session_->get_last_flt_span_id()), K(session_->get_last_flt_trace_id()));
|
|
show_trace_arr_.reset();
|
|
} else {
|
|
// recursively generate span tree
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < root_arr.count(); ++i) {
|
|
if (OB_ISNULL(root_arr.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null", K(i));
|
|
} else if (OB_FAIL(tmp_arr.push_back(root_arr.at(i)))) {
|
|
LOG_WARN("failed to add root span to array", K(ret), K(i));
|
|
} else if (OB_FAIL(find_child_span_info(NULL, root_arr.at(i)->data_.span_id_, tmp_arr, depth+1))) {
|
|
LOG_WARN("failed to find child span info", K(ret));
|
|
} else {
|
|
// do nothing
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
// do nothing
|
|
} else {
|
|
show_trace_arr_.reset();
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < tmp_arr.count(); ++i) {
|
|
if (OB_ISNULL(tmp_arr.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null", K(i));
|
|
} else {
|
|
if (is_row_format_) {
|
|
OZ(format_flt_show_trace_record(*tmp_arr.at(i)));
|
|
} else {
|
|
// do nothing
|
|
}
|
|
OZ(show_trace_arr_.push_back(tmp_arr.at(i)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LOG_TRACE("after push back show_trace record", K(show_trace_arr_.count()), K(ret));
|
|
return ret;
|
|
}
|
|
|
|
// before generate tree, we should merge span info.
|
|
// for spans, when buffer is full, it will flush.
|
|
int ObVirtualShowTrace::merge_span_info() {
|
|
int ret = OB_SUCCESS;
|
|
if (show_trace_arr_.count() < 1) {
|
|
// do nothing
|
|
} else {
|
|
ObSEArray<sql::ObFLTShowTraceRec*, 16> tmp_arr;
|
|
std::sort(&show_trace_arr_.at(0), &show_trace_arr_.at(0) + show_trace_arr_.count(),
|
|
[](const sql::ObFLTShowTraceRec* rec1, const sql::ObFLTShowTraceRec* rec2) {
|
|
if (NULL == rec1) {
|
|
return true;
|
|
} else if (NULL == rec2) {
|
|
return false;
|
|
} else {
|
|
return rec1->data_.span_id_ < rec2->data_.span_id_;
|
|
}
|
|
});
|
|
for (int64_t l=0; OB_SUCC(ret) && l < show_trace_arr_.count(); l++) {
|
|
int64_t r = l;
|
|
// if span id is same, just merge it.
|
|
if (OB_ISNULL(show_trace_arr_.at(l))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null", K(l));
|
|
} else {
|
|
ObString l_span_id = show_trace_arr_.at(l)->data_.span_id_;
|
|
while (OB_SUCC(ret) &&
|
|
r+1 < show_trace_arr_.count() &&
|
|
OB_NOT_NULL(show_trace_arr_.at(r+1)) &&
|
|
l_span_id == show_trace_arr_.at(r+1)->data_.span_id_) {
|
|
r++;
|
|
}
|
|
|
|
if (r+1 < show_trace_arr_.count()
|
|
&& OB_ISNULL(show_trace_arr_.at(r+1))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null", K(r+1));
|
|
} else {
|
|
sql::ObFLTShowTraceRec* rec;
|
|
if (OB_FAIL(alloc_trace_rec(rec))) {
|
|
SERVER_LOG(WARN, "failed to alloc record", K(ret));
|
|
} else if (OB_ISNULL(rec)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null");
|
|
} else {
|
|
OZ(merge_range_span_info(l, r, *rec));
|
|
OZ(tmp_arr.push_back(rec));
|
|
l = r;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
// do nothong
|
|
} else {
|
|
show_trace_arr_.reset();
|
|
for (int i = 0; i < tmp_arr.count(); i++) {
|
|
OZ(show_trace_arr_.push_back(tmp_arr.at(i)));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObVirtualShowTrace::merge_range_span_info(int64_t l, int64_t r, sql::ObFLTShowTraceRec &rec)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
char *tag_buf = NULL;
|
|
if (OB_ISNULL(show_trace_arr_.at(l))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null");
|
|
} else if (FALSE_IT(rec = *show_trace_arr_.at(l))) {
|
|
// do nothing
|
|
} else if (OB_FAIL(get_tag_buf(tag_buf))) {
|
|
SERVER_LOG(WARN, "failed to get tag buf", K(ret));
|
|
} else {
|
|
// merge tags
|
|
int64_t pos = 0;
|
|
MEMSET(tag_buf, 0x00, OB_MAX_SPAN_TAG_LENGTH);
|
|
tag_buf[0] = '[';
|
|
pos++;
|
|
for (int64_t i = l; OB_SUCC(ret) && i < r+1; i++) {
|
|
if (OB_ISNULL(show_trace_arr_.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null");
|
|
} else {
|
|
rec.data_.end_ts_ = max(rec.data_.end_ts_, show_trace_arr_.at(i)->data_.end_ts_);
|
|
ObString str = show_trace_arr_.at(i)->data_.tags_.trim();
|
|
if (str.length() == 0) {
|
|
// skip
|
|
} else if (pos + str.length() + 1 > OB_MAX_SPAN_TAG_LENGTH) {
|
|
// skip
|
|
} else {
|
|
MEMCPY(tag_buf+pos, str.ptr(), str.length());
|
|
pos += str.length();
|
|
tag_buf[pos] = ',';
|
|
pos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pos == 1) {
|
|
rec.data_.tags_.reset();
|
|
} else {
|
|
tag_buf[pos-1] = ']';
|
|
if (OB_FAIL(ob_write_string(alloc_, ObString(pos, tag_buf), rec.data_.tags_))) {
|
|
SERVER_LOG(WARN, "failed to deep copy log", K(ret));
|
|
}
|
|
}
|
|
|
|
// merge logs
|
|
pos = 0;
|
|
MEMSET(tag_buf, 0x00, OB_MAX_SPAN_TAG_LENGTH);
|
|
tag_buf[0] = '[';
|
|
pos++;
|
|
for (int64_t i = l; OB_SUCC(ret) && i < r+1; i++) {
|
|
if (OB_ISNULL(show_trace_arr_.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null");
|
|
} else {
|
|
ObString str = show_trace_arr_.at(i)->data_.logs_.trim();
|
|
if (str.length() == 0) {
|
|
// skip
|
|
} else if (pos + str.length() + 1 > OB_MAX_SPAN_TAG_LENGTH) {
|
|
// skip
|
|
} else {
|
|
MEMCPY(tag_buf+pos, str.ptr(), str.length());
|
|
pos += str.length();
|
|
tag_buf[pos] = ',';
|
|
pos++;
|
|
}
|
|
}
|
|
}
|
|
if (pos == 1) {
|
|
rec.data_.logs_.reset();
|
|
} else {
|
|
tag_buf[pos-1] = ']';
|
|
if (OB_FAIL(ob_write_string(alloc_, ObString(pos, tag_buf), rec.data_.logs_))) {
|
|
SERVER_LOG(WARN, "failed to deep copy log", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObVirtualShowTrace::format_flt_show_trace_record(sql::ObFLTShowTraceRec &rec)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
static const char *colors[] = {
|
|
"\033[32m", // GREEN
|
|
"\033[33m", // ORANGE
|
|
"\033[35m", // PURPLE
|
|
"\033[91m", // LIGHTRED
|
|
"\033[92m", // LIGHTGREEN
|
|
"\033[93m", // YELLOW
|
|
"\033[94m", // LIGHTBLUE
|
|
"\033[95m", // PINK
|
|
"\033[96m", // LIGHTCYAN
|
|
"\033[1;31m", // RED
|
|
"\033[1;34m" // BLUE
|
|
};
|
|
const char *color_end = "\033[0m";
|
|
char* name_buf = NULL;
|
|
const sql::ObFLTShowTraceRec::trace_formatter::NameLeftPadding &pad = rec.formatter_;
|
|
int pad_len = max(sizeof("└── "), max(sizeof("├── "), max(sizeof("│ "), sizeof(" "))));
|
|
int64_t len = pad.level_*pad_len + rec.data_.span_name_.length();
|
|
name_buf = static_cast<char *>(alloc_.alloc(len));
|
|
if (NULL == name_buf) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("allocate memory failed", K(ret), K(len));
|
|
} else {
|
|
char *start_buf = name_buf;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < pad.level_; i++) {
|
|
const sql::ObFLTShowTraceRec::trace_formatter::TreeLine &tl = pad.tree_line_[i];
|
|
const char *txt = " ";
|
|
switch (tl.line_type_) {
|
|
case sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_SPACE: {
|
|
txt = " ";
|
|
break;
|
|
}
|
|
case sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_LINE: {
|
|
txt = "│ ";
|
|
break;
|
|
}
|
|
case sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_NODE: {
|
|
txt = "├── ";
|
|
break;
|
|
}
|
|
case sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_LAST_NODE: {
|
|
txt = "└── ";
|
|
break;
|
|
};
|
|
}
|
|
MEMCPY(start_buf, txt, strlen(txt));
|
|
start_buf += strlen(txt);
|
|
}
|
|
int64_t former_len = start_buf - name_buf;
|
|
MEMCPY(start_buf, rec.data_.span_name_.ptr(), rec.data_.span_name_.length());
|
|
rec.data_.span_name_.assign(name_buf, former_len+rec.data_.span_name_.length());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObVirtualShowTrace::find_child_span_info(sql::ObFLTShowTraceRec::trace_formatter::TreeLine *parent_type,
|
|
ObString parent_span_id,
|
|
ObIArray<sql::ObFLTShowTraceRec*> &arr,
|
|
int64_t depth) {
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObSEArray<sql::ObFLTShowTraceRec*, 4> tmp_arr;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < show_trace_arr_.count(); ++i) {
|
|
if (OB_ISNULL(show_trace_arr_.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null", K(i));
|
|
} else if (show_trace_arr_.at(i)->data_.parent_span_id_ == parent_span_id) {
|
|
show_trace_arr_.at(i)->formatter_.level_ = depth;
|
|
show_trace_arr_.at(i)->formatter_.tree_line_ =
|
|
static_cast<sql::ObFLTShowTraceRec::trace_formatter::TreeLine *>(alloc_.alloc(sizeof(sql::ObFLTShowTraceRec::trace_formatter::TreeLine)*depth));
|
|
if (NULL == show_trace_arr_.at(i)->formatter_.tree_line_) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("allocate memory failed", K(ret));
|
|
} else {
|
|
MEMSET(show_trace_arr_.at(i)->formatter_.tree_line_, 0, depth);
|
|
/*
|
|
for (int j=0; OB_SUCC(ret) && j < depth; j++) {
|
|
show_trace_arr_.at(i).formatter_.tree_line_[j].color_idx_ = 0;
|
|
show_trace_arr_.at(i).formatter_.tree_line_[j].line_type_
|
|
= sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_SPACE;
|
|
}
|
|
*/
|
|
}
|
|
|
|
if (OB_FAIL(tmp_arr.push_back(show_trace_arr_.at(i)))) {
|
|
LOG_WARN("failed to push back show trace value", K(ret), K(i));
|
|
}
|
|
} else {
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
// do tmp_arr sort
|
|
if (tmp_arr.count() == 0) {
|
|
// skipp sort
|
|
} else {
|
|
std::sort(&tmp_arr.at(0), &tmp_arr.at(0) + tmp_arr.count(),
|
|
[](const sql::ObFLTShowTraceRec *rec1, const sql::ObFLTShowTraceRec *rec2) {
|
|
if (NULL == rec1) {
|
|
return true;
|
|
} else if (NULL == rec2) {
|
|
return false;
|
|
} else {
|
|
return rec1->data_.start_ts_ < rec2->data_.start_ts_;
|
|
}
|
|
});
|
|
}
|
|
|
|
// copy parent's node format
|
|
for (int64_t i = 0; OB_NOT_NULL(parent_type) && OB_SUCC(ret) && i < tmp_arr.count(); ++i) {
|
|
if (OB_ISNULL(tmp_arr.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null", K(i));
|
|
} else {
|
|
sql::ObFLTShowTraceRec& rec = *tmp_arr.at(i);
|
|
for (int64_t j = 0; OB_SUCC(ret) && j < depth-1; j++) {
|
|
rec.formatter_.tree_line_[j].line_type_ = parent_type[j].line_type_;
|
|
}
|
|
sql::ObFLTShowTraceRec::trace_formatter::LineType line_type
|
|
= rec.formatter_.tree_line_[depth-2].line_type_;
|
|
if (line_type == sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_NODE) {
|
|
rec.formatter_.tree_line_[depth-2].line_type_
|
|
= sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_LINE;
|
|
} else if (line_type == sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_LAST_NODE) {
|
|
rec.formatter_.tree_line_[depth-2].line_type_
|
|
= sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_SPACE;
|
|
}
|
|
rec.formatter_.tree_line_[depth-1].line_type_
|
|
= sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_SPACE;
|
|
}
|
|
}
|
|
|
|
// process current
|
|
if (tmp_arr.count() < 1) {
|
|
// do nothing, remain space
|
|
} else if (tmp_arr.count() == 0) {
|
|
if (OB_ISNULL(tmp_arr.at(0))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null");
|
|
} else {
|
|
tmp_arr.at(0)->formatter_.tree_line_[depth-1].line_type_
|
|
= sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_LAST_NODE;
|
|
}
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < tmp_arr.count()-1; ++i) {
|
|
if (OB_ISNULL(tmp_arr.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null", K(i));
|
|
} else {
|
|
tmp_arr.at(i)->formatter_.tree_line_[depth-1].line_type_
|
|
= sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_NODE;
|
|
}
|
|
}
|
|
if (OB_ISNULL(tmp_arr.at(tmp_arr.count()-1))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null");
|
|
} else {
|
|
tmp_arr.at(tmp_arr.count()-1)->formatter_.tree_line_[depth-1].line_type_
|
|
= sql::ObFLTShowTraceRec::trace_formatter::LineType::LT_LAST_NODE;
|
|
}
|
|
}
|
|
|
|
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < tmp_arr.count(); ++i) {
|
|
if (OB_ISNULL(tmp_arr.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null", K(i));
|
|
} else if (OB_FAIL(arr.push_back(tmp_arr.at(i)))) {
|
|
LOG_WARN("failed to push back show trace value", K(ret), K(i));
|
|
} else if (OB_FAIL(find_child_span_info(tmp_arr.at(i)->formatter_.tree_line_,
|
|
tmp_arr.at(i)->data_.span_id_,
|
|
arr,
|
|
depth+1))) {
|
|
LOG_WARN("failed to push back show trace value", K(ret), K(i));
|
|
} else {
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObVirtualShowTrace::inner_get_next_row(common::ObNewRow *&row)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
// first get row
|
|
if (is_first_get_) {
|
|
bool is_valid = true;
|
|
// init inner iterator varaibales
|
|
show_trace_arr_.reset();
|
|
if (OB_FAIL(retrive_all_span_info())) {
|
|
SERVER_LOG(WARN, "failed to retrive all span info", K(ret));
|
|
} else if (OB_FAIL(merge_span_info())) {
|
|
SERVER_LOG(WARN, "failed to merge span info", K(ret));
|
|
} else if (OB_FAIL(generate_span_info_tree())) {
|
|
SERVER_LOG(WARN, "failed to generate span info tree", K(ret));
|
|
} else {
|
|
is_first_get_ = false;
|
|
show_trace_rec_idx_ = 0;
|
|
}
|
|
LOG_TRACE("after pre processed", K(show_trace_arr_.count()), K(ret));
|
|
}
|
|
|
|
// display
|
|
if (show_trace_arr_.empty()) {
|
|
// do nothing
|
|
ret = OB_ITER_END;
|
|
} else if (OB_SUCC(ret)) {
|
|
if (show_trace_rec_idx_ < 0) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "invalid operator_stat array index", K(show_trace_rec_idx_));
|
|
} else if (show_trace_rec_idx_ >= show_trace_arr_.count()) {
|
|
ret = OB_ITER_END;
|
|
show_trace_rec_idx_ = OB_INVALID_ID;
|
|
show_trace_arr_.reset();
|
|
} else if (OB_ISNULL(show_trace_arr_.at(show_trace_rec_idx_))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "record ptr is null", K(show_trace_rec_idx_));
|
|
} else {
|
|
sql::ObFLTShowTraceRec rec = *show_trace_arr_.at(show_trace_rec_idx_);
|
|
++show_trace_rec_idx_;
|
|
if (OB_FAIL(fill_cells(rec))) {
|
|
SERVER_LOG(WARN, "fail to fill cells", K(rec), K(effective_tenant_id_));
|
|
} else {
|
|
row = &cur_row_;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObVirtualShowTrace::fill_cells(sql::ObFLTShowTraceRec &record)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const int64_t col_count = output_column_ids_.count();
|
|
ObObj *cells = cur_row_.cells_;
|
|
|
|
if (OB_ISNULL(cells)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
SERVER_LOG(WARN, "invalid argument", K(cells));
|
|
} else {
|
|
for (int64_t cell_idx = 0; OB_SUCC(ret) && cell_idx < col_count; cell_idx++) {
|
|
uint64_t col_id = output_column_ids_.at(cell_idx);
|
|
switch(col_id) {
|
|
//server ip
|
|
case SVR_IP: {
|
|
cells[cell_idx].set_varchar(ipstr_); //ipstr_ and port_ were set in set_ip func call
|
|
cells[cell_idx].set_collation_type(ObCharset::get_default_collation(
|
|
ObCharset::get_default_charset()));
|
|
} break;
|
|
//server port
|
|
case SVR_PORT: {
|
|
cells[cell_idx].set_int(port_);
|
|
} break;
|
|
case TENANT_ID: {
|
|
cells[cell_idx].set_int(record.data_.tenant_id_);
|
|
} break;
|
|
case TRACE_ID: {
|
|
cells[cell_idx].set_varchar(record.data_.trace_id_);
|
|
cells[cell_idx].set_collation_type(ObCharset::get_default_collation(
|
|
ObCharset::get_default_charset()));
|
|
} break;
|
|
case REQUEST_ID: {
|
|
cells[cell_idx].set_int(record.data_.req_id_);
|
|
} break;
|
|
//rec server ip
|
|
case REC_SVR_IP: {
|
|
cells[cell_idx].set_varchar(record.ipstr_); //ipstr_ and port_ were set in set_ip func call
|
|
cells[cell_idx].set_collation_type(ObCharset::get_default_collation(
|
|
ObCharset::get_default_charset()));
|
|
} break;
|
|
//rec server port
|
|
case REC_SVR_PORT: {
|
|
cells[cell_idx].set_int(record.port_);
|
|
} break;
|
|
case SPAN_ID: {
|
|
cells[cell_idx].set_varchar(record.data_.span_id_);
|
|
cells[cell_idx].set_collation_type(ObCharset::get_default_collation(
|
|
ObCharset::get_default_charset()));
|
|
} break;
|
|
case PARENT_SPAN_ID: {
|
|
cells[cell_idx].set_varchar(record.data_.parent_span_id_);
|
|
cells[cell_idx].set_collation_type(ObCharset::get_default_collation(
|
|
ObCharset::get_default_charset()));
|
|
} break;
|
|
case SPAN_NAME: {
|
|
cells[cell_idx].set_varchar(record.data_.span_name_);
|
|
cells[cell_idx].set_collation_type(ObCharset::get_default_collation(
|
|
ObCharset::get_default_charset()));
|
|
} break;
|
|
case REF_TYPE: {
|
|
if (record.data_.ref_type_ == 0) {
|
|
cells[cell_idx].set_varchar("CHILD");
|
|
cells[cell_idx].set_collation_type(ObCharset::get_default_collation(
|
|
ObCharset::get_default_charset()));
|
|
} else if (record.data_.ref_type_ == 1) {
|
|
cells[cell_idx].set_varchar("FOLLOW");
|
|
cells[cell_idx].set_collation_type(ObCharset::get_default_collation(
|
|
ObCharset::get_default_charset()));
|
|
} else {
|
|
// do nothing
|
|
}
|
|
} break;
|
|
case START_TS: {
|
|
cells[cell_idx].set_timestamp(record.data_.start_ts_);
|
|
} break;
|
|
case END_TS: {
|
|
cells[cell_idx].set_timestamp(record.data_.end_ts_);
|
|
} break;
|
|
case ELAPSE: {
|
|
cells[cell_idx].set_int(record.data_.end_ts_ - record.data_.start_ts_);
|
|
} break;
|
|
case TAGS: {
|
|
cells[cell_idx].set_lob_value(ObLongTextType,
|
|
record.data_.tags_.ptr(),
|
|
record.data_.tags_.length());
|
|
cells[cell_idx].set_collation_type(ObCharset::get_default_collation(
|
|
ObCharset::get_default_charset()));
|
|
} break;
|
|
case LOGS: {
|
|
cells[cell_idx].set_lob_value(ObLongTextType,
|
|
record.data_.logs_.ptr(),
|
|
record.data_.logs_.length());
|
|
cells[cell_idx].set_collation_type(ObCharset::get_default_collation(
|
|
ObCharset::get_default_charset()));
|
|
} break;
|
|
default: {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SERVER_LOG(WARN, "invalid column id", K(ret), K(cell_idx), K(col_id));
|
|
} break;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObVirtualShowTrace::set_ip(common::ObAddr *addr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
MEMSET(server_ip_, 0, sizeof(server_ip_));
|
|
if (NULL == addr){
|
|
ret = OB_ENTRY_NOT_EXIST;
|
|
} else if (!addr_->ip_to_string(server_ip_, sizeof(server_ip_))) {
|
|
SERVER_LOG(ERROR, "ip to string failed");
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else {
|
|
ipstr_ = ObString::make_string(server_ip_);
|
|
port_ = addr_->get_port();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObVirtualShowTrace::alloc_trace_rec(sql::ObFLTShowTraceRec *&rec)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
char* buf = NULL;
|
|
if (NULL == (buf = (char*)alloc_.alloc(sizeof(sql::ObFLTShowTraceRec)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
if (REACH_TIME_INTERVAL(100 * 1000)) {
|
|
SERVER_LOG(WARN, "alloc mem failed", K(OB_MAX_SPAN_TAG_LENGTH), K(ret));
|
|
}
|
|
} else {
|
|
rec = new(buf)sql::ObFLTShowTraceRec();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
} //namespace observer
|
|
} //namespace oceanbase
|