github-actions[bot] commented on code in PR #16466:
URL: https://github.com/apache/doris/pull/16466#discussion_r1098272444


##########
be/src/runtime/thread_context.h:
##########
@@ -182,15 +191,24 @@
     // to nullptr, but the object it points to is not initialized. At this 
time, when the memory
     // is released somewhere, the TCMalloc hook is triggered to cause the 
crash.
     std::unique_ptr<ThreadMemTrackerMgr> thread_mem_tracker_mgr;
-    MemTrackerLimiter* thread_mem_tracker() {
+    MemTrackerLimiter* thread_mem_tracker() const {
         return thread_mem_tracker_mgr->limiter_mem_tracker_raw();
     }
 
+    // any time we need the trace context of current query/fragment/task..., 
tls_trace_ctx is it.
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    debug::QueryTraceContext tls_trace_ctx;
+#endif
+
 private:
-    std::string _task_id = "";
+    std::string _task_id;
     TUniqueId _fragment_instance_id;
 };
 
+debug::QueryTraceContext& get_tls_trace_ctx(){
+    return bthread_context->tls_trace_ctx;

Review Comment:
   warning: no member named 'tls_trace_ctx' in 'doris::ThreadContext' 
[clang-diagnostic-error]
   ```cpp
       return bthread_context->tls_trace_ctx;
                               ^
   ```
   



##########
be/src/pipeline/pipeline_task.h:
##########
@@ -171,7 +176,9 @@ class PipelineTask {
 
     bool has_dependency();
 
-    uint32_t index() const { return _index; }
+    uint32_t index() const { return _index; } // TODO: is it useful?
+
+    auto get_id() const { return _pipeline->get_id(); }
 
     OperatorPtr get_root() { return _root; }

Review Comment:
   warning: unknown type name 'OperatorPtr' [clang-diagnostic-error]
   ```cpp
       OperatorPtr get_root() { return _root; }
       ^
   ```
   



##########
be/src/util/debug/tracing.cpp:
##########
@@ -0,0 +1,207 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gen_cpp/Opcodes_types.h>
+#include <filesystem>
+#include <fstream>
+#include <mutex>
+#include <utility>
+
+#include "common/config.h"
+#include "pipeline/pipeline_task.h"
+#include "fmt/printf.h"
+#include "util/debug/tracing.h"
+#include "util/time.h"
+
+namespace doris::debug {
+
+QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,

Review Comment:
   warning: out-of-line definition of 'create' does not match any declaration 
in 'doris::debug::QueryTraceEvent' [clang-diagnostic-error]
   ```cpp
   QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,
                                    ^
   ```
   



##########
be/src/util/debug/tracing.cpp:
##########
@@ -0,0 +1,207 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gen_cpp/Opcodes_types.h>
+#include <filesystem>
+#include <fstream>
+#include <mutex>
+#include <utility>
+
+#include "common/config.h"
+#include "pipeline/pipeline_task.h"
+#include "fmt/printf.h"
+#include "util/debug/tracing.h"
+#include "util/time.h"
+
+namespace doris::debug {
+
+QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                        int64_t timestamp, int64_t duration, 
int64_t instance_id, pipeline::PipelineTaskRawPtr task,
+                                        std::vector<std::pair<std::string, 
std::string>>&& args) {
+    QueryTraceEvent event;
+    event.name = name;
+    event.category = category;
+    event.id = id;
+    event.phase = phase;
+    event.start_time = timestamp;
+    event.duration = duration;
+    event.instance_id = instance_id;
+    event.task = task;
+    event.args = std::move(args);
+    event.thread_id = std::this_thread::get_id();
+    return event;
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, const 
QueryTraceContext& ctx) {
+    return create(name, category, id, phase, MonotonicMicros() - ctx.start_ts, 
QueryTraceContext::DEFAULT_EVENT_ID,
+                  ctx.fragment_instance_id, ctx.task, {});
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, int64_t start_ts, 
int64_t duration,
+                                                 const QueryTraceContext& ctx) 
{
+    return create(name, category, id, phase, start_ts, duration, 
ctx.fragment_instance_id, ctx.task, {});
+}
+
+static const char* kSimpleEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+static const char* kCompleteEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"dur":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+
+std::string QueryTraceEvent::to_string() {
+    std::string args_str = args_to_string();
+    size_t tidx = std::hash<std::thread::id>{}(thread_id);
+
+    // transform a raw pointer to uint64_t by re_cast is maybe not the best 
way, but at least unambiguous & safe.
+    if (phase == 'X') {
+        return fmt::sprintf(kCompleteEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
duration, phase, args_str.c_str(), tidx);
+    } else {
+        return fmt::sprintf(kSimpleEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
phase, args_str.c_str(), tidx);
+    }
+}
+
+std::string QueryTraceEvent::args_to_string() {
+    if (args.empty()) {
+        return "{}";
+    }
+    std::ostringstream oss;
+    oss << "{";
+    oss << fmt::sprintf(R"("%s":"%s")", args[0].first.c_str(), 
args[0].second.c_str());
+    for (size_t i = 1; i < args.size(); i++) {
+        oss << fmt::sprintf(R"(,"%s":"%s")", args[i].first.c_str(), 
args[i].second.c_str());
+    }
+    oss << "}";
+    return oss.str();
+}
+
+void EventBuffer::add(QueryTraceEvent&& event) {
+    std::lock_guard<std::mutex> l(_mutex);
+    _buffer.emplace_back(std::move(event));
+}
+
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) : 
_query_id(query_id), _is_enable(is_enable) {
+    if (_is_enable) {
+        _start_ts = MonotonicMicros();
+    }
+}
+#else
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) {}
+#endif
+
+void QueryTrace::register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks) {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return;
+    }
+    std::unique_lock l(_mutex);
+    auto iter = _fragment_tasks.find(fragment_instance_id);
+    if (iter == _fragment_tasks.end()) {
+        _fragment_tasks.emplace(fragment_instance_id,
+                                    
std::make_shared<std::unordered_set<pipeline::PipelineTaskRawPtr>>());
+        iter = _fragment_tasks.find(fragment_instance_id);
+    }
+    for (auto& task : tasks) {
+        iter->second->insert(task); // into this fragment's task map.
+        _buffers.emplace(task, std::make_unique<EventBuffer>());

Review Comment:
   warning: use of undeclared identifier '_buffers' [clang-diagnostic-error]
   ```cpp
           _buffers.emplace(task, std::make_unique<EventBuffer>());
           ^
   ```
   



##########
be/src/util/debug/tracing.cpp:
##########
@@ -0,0 +1,207 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gen_cpp/Opcodes_types.h>
+#include <filesystem>
+#include <fstream>
+#include <mutex>
+#include <utility>
+
+#include "common/config.h"
+#include "pipeline/pipeline_task.h"
+#include "fmt/printf.h"
+#include "util/debug/tracing.h"
+#include "util/time.h"
+
+namespace doris::debug {
+
+QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                        int64_t timestamp, int64_t duration, 
int64_t instance_id, pipeline::PipelineTaskRawPtr task,
+                                        std::vector<std::pair<std::string, 
std::string>>&& args) {
+    QueryTraceEvent event;
+    event.name = name;
+    event.category = category;
+    event.id = id;
+    event.phase = phase;
+    event.start_time = timestamp;
+    event.duration = duration;
+    event.instance_id = instance_id;
+    event.task = task;
+    event.args = std::move(args);
+    event.thread_id = std::this_thread::get_id();
+    return event;
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, const 
QueryTraceContext& ctx) {
+    return create(name, category, id, phase, MonotonicMicros() - ctx.start_ts, 
QueryTraceContext::DEFAULT_EVENT_ID,
+                  ctx.fragment_instance_id, ctx.task, {});
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, int64_t start_ts, 
int64_t duration,
+                                                 const QueryTraceContext& ctx) 
{
+    return create(name, category, id, phase, start_ts, duration, 
ctx.fragment_instance_id, ctx.task, {});
+}
+
+static const char* kSimpleEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+static const char* kCompleteEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"dur":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+
+std::string QueryTraceEvent::to_string() {
+    std::string args_str = args_to_string();
+    size_t tidx = std::hash<std::thread::id>{}(thread_id);
+
+    // transform a raw pointer to uint64_t by re_cast is maybe not the best 
way, but at least unambiguous & safe.
+    if (phase == 'X') {
+        return fmt::sprintf(kCompleteEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
duration, phase, args_str.c_str(), tidx);
+    } else {
+        return fmt::sprintf(kSimpleEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
phase, args_str.c_str(), tidx);
+    }
+}
+
+std::string QueryTraceEvent::args_to_string() {
+    if (args.empty()) {
+        return "{}";
+    }
+    std::ostringstream oss;
+    oss << "{";
+    oss << fmt::sprintf(R"("%s":"%s")", args[0].first.c_str(), 
args[0].second.c_str());
+    for (size_t i = 1; i < args.size(); i++) {
+        oss << fmt::sprintf(R"(,"%s":"%s")", args[i].first.c_str(), 
args[i].second.c_str());
+    }
+    oss << "}";
+    return oss.str();
+}
+
+void EventBuffer::add(QueryTraceEvent&& event) {
+    std::lock_guard<std::mutex> l(_mutex);
+    _buffer.emplace_back(std::move(event));
+}
+
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) : 
_query_id(query_id), _is_enable(is_enable) {
+    if (_is_enable) {
+        _start_ts = MonotonicMicros();
+    }
+}
+#else
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) {}
+#endif
+
+void QueryTrace::register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks) {

Review Comment:
   warning: out-of-line definition of 'register_tasks' does not match any 
declaration in 'doris::debug::QueryTrace' [clang-diagnostic-error]
   ```cpp
   void QueryTrace::register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks) {
                    ^
   ```
   



##########
be/src/util/debug/tracing.cpp:
##########
@@ -0,0 +1,207 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gen_cpp/Opcodes_types.h>
+#include <filesystem>
+#include <fstream>
+#include <mutex>
+#include <utility>
+
+#include "common/config.h"
+#include "pipeline/pipeline_task.h"
+#include "fmt/printf.h"
+#include "util/debug/tracing.h"
+#include "util/time.h"
+
+namespace doris::debug {
+
+QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                        int64_t timestamp, int64_t duration, 
int64_t instance_id, pipeline::PipelineTaskRawPtr task,
+                                        std::vector<std::pair<std::string, 
std::string>>&& args) {
+    QueryTraceEvent event;
+    event.name = name;
+    event.category = category;
+    event.id = id;
+    event.phase = phase;
+    event.start_time = timestamp;
+    event.duration = duration;
+    event.instance_id = instance_id;
+    event.task = task;
+    event.args = std::move(args);
+    event.thread_id = std::this_thread::get_id();
+    return event;
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, const 
QueryTraceContext& ctx) {
+    return create(name, category, id, phase, MonotonicMicros() - ctx.start_ts, 
QueryTraceContext::DEFAULT_EVENT_ID,
+                  ctx.fragment_instance_id, ctx.task, {});
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, int64_t start_ts, 
int64_t duration,
+                                                 const QueryTraceContext& ctx) 
{
+    return create(name, category, id, phase, start_ts, duration, 
ctx.fragment_instance_id, ctx.task, {});
+}
+
+static const char* kSimpleEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+static const char* kCompleteEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"dur":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+
+std::string QueryTraceEvent::to_string() {
+    std::string args_str = args_to_string();
+    size_t tidx = std::hash<std::thread::id>{}(thread_id);
+
+    // transform a raw pointer to uint64_t by re_cast is maybe not the best 
way, but at least unambiguous & safe.
+    if (phase == 'X') {
+        return fmt::sprintf(kCompleteEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
duration, phase, args_str.c_str(), tidx);
+    } else {
+        return fmt::sprintf(kSimpleEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
phase, args_str.c_str(), tidx);
+    }
+}
+
+std::string QueryTraceEvent::args_to_string() {
+    if (args.empty()) {
+        return "{}";
+    }
+    std::ostringstream oss;
+    oss << "{";
+    oss << fmt::sprintf(R"("%s":"%s")", args[0].first.c_str(), 
args[0].second.c_str());
+    for (size_t i = 1; i < args.size(); i++) {
+        oss << fmt::sprintf(R"(,"%s":"%s")", args[i].first.c_str(), 
args[i].second.c_str());
+    }
+    oss << "}";
+    return oss.str();
+}
+
+void EventBuffer::add(QueryTraceEvent&& event) {
+    std::lock_guard<std::mutex> l(_mutex);
+    _buffer.emplace_back(std::move(event));
+}
+
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) : 
_query_id(query_id), _is_enable(is_enable) {
+    if (_is_enable) {
+        _start_ts = MonotonicMicros();
+    }
+}
+#else
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) {}
+#endif
+
+void QueryTrace::register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks) {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return;
+    }
+    std::unique_lock l(_mutex);
+    auto iter = _fragment_tasks.find(fragment_instance_id);
+    if (iter == _fragment_tasks.end()) {
+        _fragment_tasks.emplace(fragment_instance_id,
+                                    
std::make_shared<std::unordered_set<pipeline::PipelineTaskRawPtr>>());
+        iter = _fragment_tasks.find(fragment_instance_id);
+    }
+    for (auto& task : tasks) {
+        iter->second->insert(task); // into this fragment's task map.
+        _buffers.emplace(task, std::make_unique<EventBuffer>());
+    }
+#endif
+}
+
+Status QueryTrace::dump() {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return Status::OK();
+    }
+    static const char* kProcessNameMetaEventFormat =
+            
"{\"name\":\"process_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    static const char* kThreadNameMetaEventFormat =
+            
"{\"name\":\"thread_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"tid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    try {
+        std::filesystem::create_directory(doris::config::tracing_dir);
+        std::string file_name =
+                fmt::format("{}/{}.json", doris::config::tracing_dir, 
print_id(_query_id));
+        std::ofstream oss(file_name.c_str(), std::ios::out | std::ios::binary);
+        oss << "{\"traceEvents\":[\n";
+        bool is_first = true;
+        for (auto& [fragment_id, task_set] : _fragment_tasks) {
+            std::string fragment_id_str = print_id(fragment_id);
+            oss << (is_first ? "" : ",\n");
+            oss << fmt::sprintf(kProcessNameMetaEventFormat, 
(uint64_t)fragment_id.lo, fragment_id_str.c_str());
+            is_first = false;
+            for (auto& task : *task_set) {
+                pipeline::PipelineTaskRawPtr ptr = 
reinterpret_cast<pipeline::PipelineTaskRawPtr>(task);
+                oss << (is_first ? "" : ",\n");
+                oss << fmt::sprintf(kThreadNameMetaEventFormat, 
(uint64_t)fragment_id.lo, reinterpret_cast<uint64_t>(task.get()),
+                                    std::to_string(ptr->get_id()));
+            }
+        }
+
+        for (auto& [_, buffer_ptr] : _buffers) {
+            auto& buffer = buffer_ptr->_buffer;
+            for (auto iter : buffer) {
+                oss << (is_first ? "" : ",\n");
+                oss << iter.to_string();
+            }
+        }
+        oss << "\n]}";
+
+        oss.close();
+    } catch (std::exception& e) {
+        return Status::IOError(fmt::format("dump trace log error {}", 
e.what()));
+    }
+#endif
+    return Status::OK();
+}
+
+void QueryTrace::set_tls_trace_context(QueryTrace* query_trace, const 
TUniqueId& fragment_instance_id,
+                                       pipeline::PipelineTaskRawPtr task) {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!query_trace->_is_enable) {
+        tls_trace_ctx.reset();
+        return;
+    }
+    {
+        std::shared_lock l(query_trace->_mutex);
+        auto iter = query_trace->_buffers.find(task);
+        DCHECK(iter != query_trace->_buffers.end());

Review Comment:
   warning: no member named '_buffers' in 'doris::debug::QueryTrace' 
[clang-diagnostic-error]
   ```cpp
           DCHECK(iter != query_trace->_buffers.end());
                                       ^
   ```
   **thirdparty/installed/include/glog/logging.h:1043:** expanded from macro 
'DCHECK'
   ```cpp
       GLOG_MSVC_POP_WARNING() CHECK(condition)
                                     ^
   ```
   **thirdparty/installed/include/glog/logging.h:592:** expanded from macro 
'CHECK'
   ```cpp
         LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
                                                         ^
   ```
   **thirdparty/installed/include/glog/logging.h:131:** expanded from macro 
'GOOGLE_PREDICT_BRANCH_NOT_TAKEN'
   ```cpp
   #define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))
                                                                ^
   ```
   **thirdparty/installed/include/glog/logging.h:577:** expanded from macro 
'LOG_IF'
   ```cpp
     !(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
       ^
   ```
   



##########
be/src/util/debug/tracing.h:
##########
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <deque>
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <shared_mutex>
+#include <string>
+#include <unordered_set>
+#include <thread>
+
+#include "common/status.h"
+#include "gen_cpp/Types_types.h"
+#include "pipeline/pipeline_task.h"
+
+#define ENABLE_QUERY_DEBUG_TRACE
+
+// The whole function is control by marco in building. if the function is 
turned off, no entity will be construct.
+// In another word, it's zero-overhead.
+
+namespace doris::debug {
+
+class QueryTraceContext;
+
+/// QueryTraceEvent saves a specific event info.
+class QueryTraceEvent {
+public:
+    std::string name;
+    std::string category;
+    int64_t id; // used for async event
+    char phase; // type of event
+    int64_t start_time;
+    int64_t duration = -1; // used only in compelete event
+    decltype(TUniqueId::lo) instance_id;
+    pipeline::PipelineTaskRawPtr task; // task pointer
+    std::thread::id thread_id;
+    std::vector<std::pair<std::string, std::string>> args;
+
+    std::string to_string();
+
+    static QueryTraceEvent create(const std::string& name, const std::string& 
category, int64_t id, char phase,
+                                  int64_t timestamp, int64_t duration, int64_t 
instance_id, pipeline::PipelineTaskRawPtr task,
+                                  std::vector<std::pair<std::string, 
std::string>>&& args);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           const QueryTraceContext& ctx);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           int64_t start_ts, int64_t duration, 
const QueryTraceContext& ctx);
+
+private:
+    std::string args_to_string();
+};
+
+/// Event buffer for a single PipelineTask.
+/// didn't store in threads' own trace_context, but in QueryTrace.
+class EventBuffer {
+public:
+    EventBuffer() = default;
+    ~EventBuffer() = default;
+
+    void add(QueryTraceEvent&& event);
+
+private:
+    friend class QueryTrace;
+    std::mutex _mutex;
+    std::deque<QueryTraceEvent> _buffer;
+};
+
+class QueryTrace {
+public:
+    QueryTrace(const TUniqueId& query_id, bool is_enable);
+    ~QueryTrace() = default;
+
+    // init event buffer for all tasks in a single fragment instance
+    void register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks);
+
+    Status dump();
+
+    static void set_tls_trace_context(QueryTrace* query_trace, const 
TUniqueId& fragment_instance_id,
+                                      pipeline::PipelineTaskRawPtr task);

Review Comment:
   warning: no type named 'PipelineTaskRawPtr' in namespace 'doris::pipeline' 
[clang-diagnostic-error]
   ```cpp
                                         pipeline::PipelineTaskRawPtr task);
                                                   ^
   ```
   



##########
be/src/util/debug/tracing.cpp:
##########
@@ -0,0 +1,207 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gen_cpp/Opcodes_types.h>
+#include <filesystem>
+#include <fstream>
+#include <mutex>
+#include <utility>
+
+#include "common/config.h"
+#include "pipeline/pipeline_task.h"
+#include "fmt/printf.h"
+#include "util/debug/tracing.h"
+#include "util/time.h"
+
+namespace doris::debug {
+
+QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                        int64_t timestamp, int64_t duration, 
int64_t instance_id, pipeline::PipelineTaskRawPtr task,
+                                        std::vector<std::pair<std::string, 
std::string>>&& args) {
+    QueryTraceEvent event;
+    event.name = name;
+    event.category = category;
+    event.id = id;
+    event.phase = phase;
+    event.start_time = timestamp;
+    event.duration = duration;
+    event.instance_id = instance_id;
+    event.task = task;
+    event.args = std::move(args);
+    event.thread_id = std::this_thread::get_id();
+    return event;
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, const 
QueryTraceContext& ctx) {
+    return create(name, category, id, phase, MonotonicMicros() - ctx.start_ts, 
QueryTraceContext::DEFAULT_EVENT_ID,
+                  ctx.fragment_instance_id, ctx.task, {});
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, int64_t start_ts, 
int64_t duration,
+                                                 const QueryTraceContext& ctx) 
{
+    return create(name, category, id, phase, start_ts, duration, 
ctx.fragment_instance_id, ctx.task, {});
+}
+
+static const char* kSimpleEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+static const char* kCompleteEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"dur":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+
+std::string QueryTraceEvent::to_string() {
+    std::string args_str = args_to_string();
+    size_t tidx = std::hash<std::thread::id>{}(thread_id);
+
+    // transform a raw pointer to uint64_t by re_cast is maybe not the best 
way, but at least unambiguous & safe.
+    if (phase == 'X') {
+        return fmt::sprintf(kCompleteEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
duration, phase, args_str.c_str(), tidx);
+    } else {
+        return fmt::sprintf(kSimpleEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
phase, args_str.c_str(), tidx);
+    }
+}
+
+std::string QueryTraceEvent::args_to_string() {
+    if (args.empty()) {
+        return "{}";
+    }
+    std::ostringstream oss;
+    oss << "{";
+    oss << fmt::sprintf(R"("%s":"%s")", args[0].first.c_str(), 
args[0].second.c_str());
+    for (size_t i = 1; i < args.size(); i++) {
+        oss << fmt::sprintf(R"(,"%s":"%s")", args[i].first.c_str(), 
args[i].second.c_str());
+    }
+    oss << "}";
+    return oss.str();
+}
+
+void EventBuffer::add(QueryTraceEvent&& event) {
+    std::lock_guard<std::mutex> l(_mutex);
+    _buffer.emplace_back(std::move(event));
+}
+
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) : 
_query_id(query_id), _is_enable(is_enable) {
+    if (_is_enable) {
+        _start_ts = MonotonicMicros();
+    }
+}
+#else
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) {}
+#endif
+
+void QueryTrace::register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks) {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return;
+    }
+    std::unique_lock l(_mutex);
+    auto iter = _fragment_tasks.find(fragment_instance_id);
+    if (iter == _fragment_tasks.end()) {
+        _fragment_tasks.emplace(fragment_instance_id,
+                                    
std::make_shared<std::unordered_set<pipeline::PipelineTaskRawPtr>>());
+        iter = _fragment_tasks.find(fragment_instance_id);
+    }
+    for (auto& task : tasks) {
+        iter->second->insert(task); // into this fragment's task map.
+        _buffers.emplace(task, std::make_unique<EventBuffer>());
+    }
+#endif
+}
+
+Status QueryTrace::dump() {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return Status::OK();
+    }
+    static const char* kProcessNameMetaEventFormat =
+            
"{\"name\":\"process_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    static const char* kThreadNameMetaEventFormat =
+            
"{\"name\":\"thread_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"tid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    try {
+        std::filesystem::create_directory(doris::config::tracing_dir);
+        std::string file_name =
+                fmt::format("{}/{}.json", doris::config::tracing_dir, 
print_id(_query_id));
+        std::ofstream oss(file_name.c_str(), std::ios::out | std::ios::binary);
+        oss << "{\"traceEvents\":[\n";
+        bool is_first = true;
+        for (auto& [fragment_id, task_set] : _fragment_tasks) {
+            std::string fragment_id_str = print_id(fragment_id);
+            oss << (is_first ? "" : ",\n");
+            oss << fmt::sprintf(kProcessNameMetaEventFormat, 
(uint64_t)fragment_id.lo, fragment_id_str.c_str());
+            is_first = false;
+            for (auto& task : *task_set) {
+                pipeline::PipelineTaskRawPtr ptr = 
reinterpret_cast<pipeline::PipelineTaskRawPtr>(task);
+                oss << (is_first ? "" : ",\n");
+                oss << fmt::sprintf(kThreadNameMetaEventFormat, 
(uint64_t)fragment_id.lo, reinterpret_cast<uint64_t>(task.get()),
+                                    std::to_string(ptr->get_id()));
+            }
+        }
+
+        for (auto& [_, buffer_ptr] : _buffers) {
+            auto& buffer = buffer_ptr->_buffer;
+            for (auto iter : buffer) {
+                oss << (is_first ? "" : ",\n");
+                oss << iter.to_string();
+            }
+        }
+        oss << "\n]}";
+
+        oss.close();
+    } catch (std::exception& e) {
+        return Status::IOError(fmt::format("dump trace log error {}", 
e.what()));
+    }
+#endif
+    return Status::OK();
+}
+
+void QueryTrace::set_tls_trace_context(QueryTrace* query_trace, const 
TUniqueId& fragment_instance_id,
+                                       pipeline::PipelineTaskRawPtr task) {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!query_trace->_is_enable) {
+        tls_trace_ctx.reset();

Review Comment:
   warning: member reference base type 'debug::QueryTraceContext &()' is not a 
structure or union [clang-diagnostic-error]
   ```cpp
           tls_trace_ctx.reset();
                        ^
   ```
   



##########
be/src/runtime/thread_context.h:
##########
@@ -182,15 +191,24 @@ class ThreadContext {
     // to nullptr, but the object it points to is not initialized. At this 
time, when the memory
     // is released somewhere, the TCMalloc hook is triggered to cause the 
crash.
     std::unique_ptr<ThreadMemTrackerMgr> thread_mem_tracker_mgr;
-    MemTrackerLimiter* thread_mem_tracker() {
+    MemTrackerLimiter* thread_mem_tracker() const {
         return thread_mem_tracker_mgr->limiter_mem_tracker_raw();
     }
 
+    // any time we need the trace context of current query/fragment/task..., 
tls_trace_ctx is it.
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    debug::QueryTraceContext tls_trace_ctx;
+#endif
+
 private:
-    std::string _task_id = "";
+    std::string _task_id;
     TUniqueId _fragment_instance_id;
 };
 
+debug::QueryTraceContext& get_tls_trace_ctx(){

Review Comment:
   warning: no type named 'QueryTraceContext' in namespace 'doris::debug' 
[clang-diagnostic-error]
   ```cpp
   debug::QueryTraceContext& get_tls_trace_ctx(){
          ^
   ```
   



##########
be/src/util/debug/tracing.cpp:
##########
@@ -0,0 +1,207 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gen_cpp/Opcodes_types.h>
+#include <filesystem>
+#include <fstream>
+#include <mutex>
+#include <utility>
+
+#include "common/config.h"
+#include "pipeline/pipeline_task.h"
+#include "fmt/printf.h"
+#include "util/debug/tracing.h"
+#include "util/time.h"
+
+namespace doris::debug {
+
+QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                        int64_t timestamp, int64_t duration, 
int64_t instance_id, pipeline::PipelineTaskRawPtr task,
+                                        std::vector<std::pair<std::string, 
std::string>>&& args) {
+    QueryTraceEvent event;
+    event.name = name;
+    event.category = category;
+    event.id = id;
+    event.phase = phase;
+    event.start_time = timestamp;
+    event.duration = duration;
+    event.instance_id = instance_id;
+    event.task = task;
+    event.args = std::move(args);
+    event.thread_id = std::this_thread::get_id();
+    return event;
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, const 
QueryTraceContext& ctx) {
+    return create(name, category, id, phase, MonotonicMicros() - ctx.start_ts, 
QueryTraceContext::DEFAULT_EVENT_ID,

Review Comment:
   warning: call to non-static member function without an object argument 
[clang-diagnostic-error]
   ```cpp
       return create(name, category, id, phase, MonotonicMicros() - 
ctx.start_ts, QueryTraceContext::DEFAULT_EVENT_ID,
              ^
   ```
   



##########
be/src/util/debug/tracing.cpp:
##########
@@ -0,0 +1,207 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gen_cpp/Opcodes_types.h>
+#include <filesystem>
+#include <fstream>
+#include <mutex>
+#include <utility>
+
+#include "common/config.h"
+#include "pipeline/pipeline_task.h"
+#include "fmt/printf.h"
+#include "util/debug/tracing.h"
+#include "util/time.h"
+
+namespace doris::debug {
+
+QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                        int64_t timestamp, int64_t duration, 
int64_t instance_id, pipeline::PipelineTaskRawPtr task,
+                                        std::vector<std::pair<std::string, 
std::string>>&& args) {
+    QueryTraceEvent event;
+    event.name = name;
+    event.category = category;
+    event.id = id;
+    event.phase = phase;
+    event.start_time = timestamp;
+    event.duration = duration;
+    event.instance_id = instance_id;
+    event.task = task;
+    event.args = std::move(args);
+    event.thread_id = std::this_thread::get_id();
+    return event;
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, const 
QueryTraceContext& ctx) {
+    return create(name, category, id, phase, MonotonicMicros() - ctx.start_ts, 
QueryTraceContext::DEFAULT_EVENT_ID,
+                  ctx.fragment_instance_id, ctx.task, {});
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, int64_t start_ts, 
int64_t duration,
+                                                 const QueryTraceContext& ctx) 
{
+    return create(name, category, id, phase, start_ts, duration, 
ctx.fragment_instance_id, ctx.task, {});

Review Comment:
   warning: call to non-static member function without an object argument 
[clang-diagnostic-error]
   ```cpp
       return create(name, category, id, phase, start_ts, duration, 
ctx.fragment_instance_id, ctx.task, {});
              ^
   ```
   



##########
be/src/util/debug/tracing.cpp:
##########
@@ -0,0 +1,207 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gen_cpp/Opcodes_types.h>
+#include <filesystem>
+#include <fstream>
+#include <mutex>
+#include <utility>
+
+#include "common/config.h"
+#include "pipeline/pipeline_task.h"
+#include "fmt/printf.h"
+#include "util/debug/tracing.h"
+#include "util/time.h"
+
+namespace doris::debug {
+
+QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                        int64_t timestamp, int64_t duration, 
int64_t instance_id, pipeline::PipelineTaskRawPtr task,
+                                        std::vector<std::pair<std::string, 
std::string>>&& args) {
+    QueryTraceEvent event;
+    event.name = name;
+    event.category = category;
+    event.id = id;
+    event.phase = phase;
+    event.start_time = timestamp;
+    event.duration = duration;
+    event.instance_id = instance_id;
+    event.task = task;
+    event.args = std::move(args);
+    event.thread_id = std::this_thread::get_id();
+    return event;
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, const 
QueryTraceContext& ctx) {
+    return create(name, category, id, phase, MonotonicMicros() - ctx.start_ts, 
QueryTraceContext::DEFAULT_EVENT_ID,
+                  ctx.fragment_instance_id, ctx.task, {});
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, int64_t start_ts, 
int64_t duration,
+                                                 const QueryTraceContext& ctx) 
{
+    return create(name, category, id, phase, start_ts, duration, 
ctx.fragment_instance_id, ctx.task, {});
+}
+
+static const char* kSimpleEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+static const char* kCompleteEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"dur":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+
+std::string QueryTraceEvent::to_string() {
+    std::string args_str = args_to_string();
+    size_t tidx = std::hash<std::thread::id>{}(thread_id);
+
+    // transform a raw pointer to uint64_t by re_cast is maybe not the best 
way, but at least unambiguous & safe.
+    if (phase == 'X') {
+        return fmt::sprintf(kCompleteEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
duration, phase, args_str.c_str(), tidx);
+    } else {
+        return fmt::sprintf(kSimpleEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
phase, args_str.c_str(), tidx);
+    }
+}
+
+std::string QueryTraceEvent::args_to_string() {
+    if (args.empty()) {
+        return "{}";
+    }
+    std::ostringstream oss;
+    oss << "{";
+    oss << fmt::sprintf(R"("%s":"%s")", args[0].first.c_str(), 
args[0].second.c_str());
+    for (size_t i = 1; i < args.size(); i++) {
+        oss << fmt::sprintf(R"(,"%s":"%s")", args[i].first.c_str(), 
args[i].second.c_str());
+    }
+    oss << "}";
+    return oss.str();
+}
+
+void EventBuffer::add(QueryTraceEvent&& event) {
+    std::lock_guard<std::mutex> l(_mutex);
+    _buffer.emplace_back(std::move(event));
+}
+
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) : 
_query_id(query_id), _is_enable(is_enable) {
+    if (_is_enable) {
+        _start_ts = MonotonicMicros();
+    }
+}
+#else
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) {}
+#endif
+
+void QueryTrace::register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks) {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return;
+    }
+    std::unique_lock l(_mutex);
+    auto iter = _fragment_tasks.find(fragment_instance_id);
+    if (iter == _fragment_tasks.end()) {
+        _fragment_tasks.emplace(fragment_instance_id,
+                                    
std::make_shared<std::unordered_set<pipeline::PipelineTaskRawPtr>>());
+        iter = _fragment_tasks.find(fragment_instance_id);
+    }
+    for (auto& task : tasks) {
+        iter->second->insert(task); // into this fragment's task map.
+        _buffers.emplace(task, std::make_unique<EventBuffer>());
+    }
+#endif
+}
+
+Status QueryTrace::dump() {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return Status::OK();
+    }
+    static const char* kProcessNameMetaEventFormat =
+            
"{\"name\":\"process_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    static const char* kThreadNameMetaEventFormat =
+            
"{\"name\":\"thread_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"tid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    try {
+        std::filesystem::create_directory(doris::config::tracing_dir);
+        std::string file_name =
+                fmt::format("{}/{}.json", doris::config::tracing_dir, 
print_id(_query_id));
+        std::ofstream oss(file_name.c_str(), std::ios::out | std::ios::binary);
+        oss << "{\"traceEvents\":[\n";
+        bool is_first = true;
+        for (auto& [fragment_id, task_set] : _fragment_tasks) {
+            std::string fragment_id_str = print_id(fragment_id);
+            oss << (is_first ? "" : ",\n");
+            oss << fmt::sprintf(kProcessNameMetaEventFormat, 
(uint64_t)fragment_id.lo, fragment_id_str.c_str());
+            is_first = false;
+            for (auto& task : *task_set) {
+                pipeline::PipelineTaskRawPtr ptr = 
reinterpret_cast<pipeline::PipelineTaskRawPtr>(task);
+                oss << (is_first ? "" : ",\n");
+                oss << fmt::sprintf(kThreadNameMetaEventFormat, 
(uint64_t)fragment_id.lo, reinterpret_cast<uint64_t>(task.get()),
+                                    std::to_string(ptr->get_id()));
+            }
+        }
+
+        for (auto& [_, buffer_ptr] : _buffers) {

Review Comment:
   warning: use of undeclared identifier '_buffers' [clang-diagnostic-error]
   ```cpp
           for (auto& [_, buffer_ptr] : _buffers) {
                                        ^
   ```
   



##########
be/src/util/debug/tracing.h:
##########
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <deque>
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <shared_mutex>
+#include <string>
+#include <unordered_set>
+#include <thread>
+
+#include "common/status.h"
+#include "gen_cpp/Types_types.h"
+#include "pipeline/pipeline_task.h"
+
+#define ENABLE_QUERY_DEBUG_TRACE
+
+// The whole function is control by marco in building. if the function is 
turned off, no entity will be construct.
+// In another word, it's zero-overhead.
+
+namespace doris::debug {
+
+class QueryTraceContext;
+
+/// QueryTraceEvent saves a specific event info.
+class QueryTraceEvent {
+public:
+    std::string name;
+    std::string category;
+    int64_t id; // used for async event
+    char phase; // type of event
+    int64_t start_time;
+    int64_t duration = -1; // used only in compelete event
+    decltype(TUniqueId::lo) instance_id;
+    pipeline::PipelineTaskRawPtr task; // task pointer
+    std::thread::id thread_id;
+    std::vector<std::pair<std::string, std::string>> args;
+
+    std::string to_string();
+
+    static QueryTraceEvent create(const std::string& name, const std::string& 
category, int64_t id, char phase,
+                                  int64_t timestamp, int64_t duration, int64_t 
instance_id, pipeline::PipelineTaskRawPtr task,
+                                  std::vector<std::pair<std::string, 
std::string>>&& args);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           const QueryTraceContext& ctx);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           int64_t start_ts, int64_t duration, 
const QueryTraceContext& ctx);
+
+private:
+    std::string args_to_string();
+};
+
+/// Event buffer for a single PipelineTask.
+/// didn't store in threads' own trace_context, but in QueryTrace.
+class EventBuffer {
+public:
+    EventBuffer() = default;
+    ~EventBuffer() = default;
+
+    void add(QueryTraceEvent&& event);
+
+private:
+    friend class QueryTrace;
+    std::mutex _mutex;
+    std::deque<QueryTraceEvent> _buffer;
+};
+
+class QueryTrace {
+public:
+    QueryTrace(const TUniqueId& query_id, bool is_enable);
+    ~QueryTrace() = default;
+
+    // init event buffer for all tasks in a single fragment instance
+    void register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks);

Review Comment:
   warning: no type named 'PipelineTasks' in namespace 'doris::pipeline' 
[clang-diagnostic-error]
   ```cpp
       void register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks);
                                                                            ^
   ```
   



##########
be/src/util/debug/tracing.cpp:
##########
@@ -0,0 +1,207 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gen_cpp/Opcodes_types.h>
+#include <filesystem>
+#include <fstream>
+#include <mutex>
+#include <utility>
+
+#include "common/config.h"
+#include "pipeline/pipeline_task.h"
+#include "fmt/printf.h"
+#include "util/debug/tracing.h"
+#include "util/time.h"
+
+namespace doris::debug {
+
+QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                        int64_t timestamp, int64_t duration, 
int64_t instance_id, pipeline::PipelineTaskRawPtr task,
+                                        std::vector<std::pair<std::string, 
std::string>>&& args) {
+    QueryTraceEvent event;
+    event.name = name;
+    event.category = category;
+    event.id = id;
+    event.phase = phase;
+    event.start_time = timestamp;
+    event.duration = duration;
+    event.instance_id = instance_id;
+    event.task = task;
+    event.args = std::move(args);
+    event.thread_id = std::this_thread::get_id();
+    return event;
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, const 
QueryTraceContext& ctx) {
+    return create(name, category, id, phase, MonotonicMicros() - ctx.start_ts, 
QueryTraceContext::DEFAULT_EVENT_ID,
+                  ctx.fragment_instance_id, ctx.task, {});
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, int64_t start_ts, 
int64_t duration,
+                                                 const QueryTraceContext& ctx) 
{
+    return create(name, category, id, phase, start_ts, duration, 
ctx.fragment_instance_id, ctx.task, {});
+}
+
+static const char* kSimpleEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+static const char* kCompleteEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"dur":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+
+std::string QueryTraceEvent::to_string() {
+    std::string args_str = args_to_string();
+    size_t tidx = std::hash<std::thread::id>{}(thread_id);
+
+    // transform a raw pointer to uint64_t by re_cast is maybe not the best 
way, but at least unambiguous & safe.
+    if (phase == 'X') {
+        return fmt::sprintf(kCompleteEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
duration, phase, args_str.c_str(), tidx);
+    } else {
+        return fmt::sprintf(kSimpleEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
phase, args_str.c_str(), tidx);
+    }
+}
+
+std::string QueryTraceEvent::args_to_string() {
+    if (args.empty()) {
+        return "{}";
+    }
+    std::ostringstream oss;
+    oss << "{";
+    oss << fmt::sprintf(R"("%s":"%s")", args[0].first.c_str(), 
args[0].second.c_str());
+    for (size_t i = 1; i < args.size(); i++) {
+        oss << fmt::sprintf(R"(,"%s":"%s")", args[i].first.c_str(), 
args[i].second.c_str());
+    }
+    oss << "}";
+    return oss.str();
+}
+
+void EventBuffer::add(QueryTraceEvent&& event) {
+    std::lock_guard<std::mutex> l(_mutex);
+    _buffer.emplace_back(std::move(event));
+}
+
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) : 
_query_id(query_id), _is_enable(is_enable) {
+    if (_is_enable) {
+        _start_ts = MonotonicMicros();
+    }
+}
+#else
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) {}
+#endif
+
+void QueryTrace::register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks) {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return;
+    }
+    std::unique_lock l(_mutex);
+    auto iter = _fragment_tasks.find(fragment_instance_id);
+    if (iter == _fragment_tasks.end()) {
+        _fragment_tasks.emplace(fragment_instance_id,
+                                    
std::make_shared<std::unordered_set<pipeline::PipelineTaskRawPtr>>());
+        iter = _fragment_tasks.find(fragment_instance_id);
+    }
+    for (auto& task : tasks) {
+        iter->second->insert(task); // into this fragment's task map.
+        _buffers.emplace(task, std::make_unique<EventBuffer>());
+    }
+#endif
+}
+
+Status QueryTrace::dump() {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return Status::OK();
+    }
+    static const char* kProcessNameMetaEventFormat =
+            
"{\"name\":\"process_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    static const char* kThreadNameMetaEventFormat =
+            
"{\"name\":\"thread_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"tid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    try {
+        std::filesystem::create_directory(doris::config::tracing_dir);
+        std::string file_name =
+                fmt::format("{}/{}.json", doris::config::tracing_dir, 
print_id(_query_id));
+        std::ofstream oss(file_name.c_str(), std::ios::out | std::ios::binary);
+        oss << "{\"traceEvents\":[\n";
+        bool is_first = true;
+        for (auto& [fragment_id, task_set] : _fragment_tasks) {
+            std::string fragment_id_str = print_id(fragment_id);
+            oss << (is_first ? "" : ",\n");
+            oss << fmt::sprintf(kProcessNameMetaEventFormat, 
(uint64_t)fragment_id.lo, fragment_id_str.c_str());
+            is_first = false;
+            for (auto& task : *task_set) {
+                pipeline::PipelineTaskRawPtr ptr = 
reinterpret_cast<pipeline::PipelineTaskRawPtr>(task);
+                oss << (is_first ? "" : ",\n");
+                oss << fmt::sprintf(kThreadNameMetaEventFormat, 
(uint64_t)fragment_id.lo, reinterpret_cast<uint64_t>(task.get()),
+                                    std::to_string(ptr->get_id()));
+            }
+        }
+
+        for (auto& [_, buffer_ptr] : _buffers) {
+            auto& buffer = buffer_ptr->_buffer;
+            for (auto iter : buffer) {
+                oss << (is_first ? "" : ",\n");
+                oss << iter.to_string();
+            }
+        }
+        oss << "\n]}";
+
+        oss.close();
+    } catch (std::exception& e) {
+        return Status::IOError(fmt::format("dump trace log error {}", 
e.what()));
+    }
+#endif
+    return Status::OK();
+}
+
+void QueryTrace::set_tls_trace_context(QueryTrace* query_trace, const 
TUniqueId& fragment_instance_id,
+                                       pipeline::PipelineTaskRawPtr task) {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!query_trace->_is_enable) {
+        tls_trace_ctx.reset();

Review Comment:
   warning: use of undeclared identifier 'tls_trace_ctx'; did you mean 
'get_tls_trace_ctx'? [clang-diagnostic-error]
   
   ```suggestion
           get_tls_trace_ctx.reset();
   ```
   **be/src/runtime/thread_context.h:207:** 'get_tls_trace_ctx' declared here
   ```cpp
   debug::QueryTraceContext& get_tls_trace_ctx(){
                             ^
   ```
   



##########
be/src/util/debug/tracing.cpp:
##########
@@ -0,0 +1,207 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gen_cpp/Opcodes_types.h>
+#include <filesystem>
+#include <fstream>
+#include <mutex>
+#include <utility>
+
+#include "common/config.h"
+#include "pipeline/pipeline_task.h"
+#include "fmt/printf.h"
+#include "util/debug/tracing.h"
+#include "util/time.h"
+
+namespace doris::debug {
+
+QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                        int64_t timestamp, int64_t duration, 
int64_t instance_id, pipeline::PipelineTaskRawPtr task,
+                                        std::vector<std::pair<std::string, 
std::string>>&& args) {
+    QueryTraceEvent event;
+    event.name = name;
+    event.category = category;
+    event.id = id;
+    event.phase = phase;
+    event.start_time = timestamp;
+    event.duration = duration;
+    event.instance_id = instance_id;
+    event.task = task;
+    event.args = std::move(args);
+    event.thread_id = std::this_thread::get_id();
+    return event;
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, const 
QueryTraceContext& ctx) {
+    return create(name, category, id, phase, MonotonicMicros() - ctx.start_ts, 
QueryTraceContext::DEFAULT_EVENT_ID,
+                  ctx.fragment_instance_id, ctx.task, {});
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, int64_t start_ts, 
int64_t duration,
+                                                 const QueryTraceContext& ctx) 
{
+    return create(name, category, id, phase, start_ts, duration, 
ctx.fragment_instance_id, ctx.task, {});
+}
+
+static const char* kSimpleEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+static const char* kCompleteEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"dur":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+
+std::string QueryTraceEvent::to_string() {
+    std::string args_str = args_to_string();
+    size_t tidx = std::hash<std::thread::id>{}(thread_id);
+
+    // transform a raw pointer to uint64_t by re_cast is maybe not the best 
way, but at least unambiguous & safe.
+    if (phase == 'X') {
+        return fmt::sprintf(kCompleteEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
duration, phase, args_str.c_str(), tidx);
+    } else {
+        return fmt::sprintf(kSimpleEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
phase, args_str.c_str(), tidx);
+    }
+}
+
+std::string QueryTraceEvent::args_to_string() {
+    if (args.empty()) {
+        return "{}";
+    }
+    std::ostringstream oss;
+    oss << "{";
+    oss << fmt::sprintf(R"("%s":"%s")", args[0].first.c_str(), 
args[0].second.c_str());
+    for (size_t i = 1; i < args.size(); i++) {
+        oss << fmt::sprintf(R"(,"%s":"%s")", args[i].first.c_str(), 
args[i].second.c_str());
+    }
+    oss << "}";
+    return oss.str();
+}
+
+void EventBuffer::add(QueryTraceEvent&& event) {
+    std::lock_guard<std::mutex> l(_mutex);
+    _buffer.emplace_back(std::move(event));
+}
+
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) : 
_query_id(query_id), _is_enable(is_enable) {
+    if (_is_enable) {
+        _start_ts = MonotonicMicros();
+    }
+}
+#else
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) {}
+#endif
+
+void QueryTrace::register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks) {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return;
+    }
+    std::unique_lock l(_mutex);
+    auto iter = _fragment_tasks.find(fragment_instance_id);
+    if (iter == _fragment_tasks.end()) {
+        _fragment_tasks.emplace(fragment_instance_id,
+                                    
std::make_shared<std::unordered_set<pipeline::PipelineTaskRawPtr>>());
+        iter = _fragment_tasks.find(fragment_instance_id);
+    }
+    for (auto& task : tasks) {
+        iter->second->insert(task); // into this fragment's task map.
+        _buffers.emplace(task, std::make_unique<EventBuffer>());
+    }
+#endif
+}
+
+Status QueryTrace::dump() {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return Status::OK();
+    }
+    static const char* kProcessNameMetaEventFormat =
+            
"{\"name\":\"process_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    static const char* kThreadNameMetaEventFormat =
+            
"{\"name\":\"thread_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"tid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    try {
+        std::filesystem::create_directory(doris::config::tracing_dir);
+        std::string file_name =
+                fmt::format("{}/{}.json", doris::config::tracing_dir, 
print_id(_query_id));
+        std::ofstream oss(file_name.c_str(), std::ios::out | std::ios::binary);
+        oss << "{\"traceEvents\":[\n";
+        bool is_first = true;
+        for (auto& [fragment_id, task_set] : _fragment_tasks) {
+            std::string fragment_id_str = print_id(fragment_id);
+            oss << (is_first ? "" : ",\n");
+            oss << fmt::sprintf(kProcessNameMetaEventFormat, 
(uint64_t)fragment_id.lo, fragment_id_str.c_str());
+            is_first = false;
+            for (auto& task : *task_set) {
+                pipeline::PipelineTaskRawPtr ptr = 
reinterpret_cast<pipeline::PipelineTaskRawPtr>(task);
+                oss << (is_first ? "" : ",\n");
+                oss << fmt::sprintf(kThreadNameMetaEventFormat, 
(uint64_t)fragment_id.lo, reinterpret_cast<uint64_t>(task.get()),
+                                    std::to_string(ptr->get_id()));
+            }
+        }
+
+        for (auto& [_, buffer_ptr] : _buffers) {
+            auto& buffer = buffer_ptr->_buffer;
+            for (auto iter : buffer) {
+                oss << (is_first ? "" : ",\n");
+                oss << iter.to_string();
+            }
+        }
+        oss << "\n]}";
+
+        oss.close();
+    } catch (std::exception& e) {
+        return Status::IOError(fmt::format("dump trace log error {}", 
e.what()));
+    }
+#endif
+    return Status::OK();
+}
+
+void QueryTrace::set_tls_trace_context(QueryTrace* query_trace, const 
TUniqueId& fragment_instance_id,

Review Comment:
   warning: out-of-line definition of 'set_tls_trace_context' does not match 
any declaration in 'doris::debug::QueryTrace' [clang-diagnostic-error]
   ```cpp
   void QueryTrace::set_tls_trace_context(QueryTrace* query_trace, const 
TUniqueId& fragment_instance_id,
                    ^
   ```
   



##########
be/src/util/debug/tracing.cpp:
##########
@@ -0,0 +1,207 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gen_cpp/Opcodes_types.h>
+#include <filesystem>
+#include <fstream>
+#include <mutex>
+#include <utility>
+
+#include "common/config.h"
+#include "pipeline/pipeline_task.h"
+#include "fmt/printf.h"
+#include "util/debug/tracing.h"
+#include "util/time.h"
+
+namespace doris::debug {
+
+QueryTraceEvent QueryTraceEvent::create(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                        int64_t timestamp, int64_t duration, 
int64_t instance_id, pipeline::PipelineTaskRawPtr task,
+                                        std::vector<std::pair<std::string, 
std::string>>&& args) {
+    QueryTraceEvent event;
+    event.name = name;
+    event.category = category;
+    event.id = id;
+    event.phase = phase;
+    event.start_time = timestamp;
+    event.duration = duration;
+    event.instance_id = instance_id;
+    event.task = task;
+    event.args = std::move(args);
+    event.thread_id = std::this_thread::get_id();
+    return event;
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, const 
QueryTraceContext& ctx) {
+    return create(name, category, id, phase, MonotonicMicros() - ctx.start_ts, 
QueryTraceContext::DEFAULT_EVENT_ID,
+                  ctx.fragment_instance_id, ctx.task, {});
+}
+
+QueryTraceEvent QueryTraceEvent::create_with_ctx(const std::string& name, 
const std::string& category, int64_t id,
+                                                 char phase, int64_t start_ts, 
int64_t duration,
+                                                 const QueryTraceContext& ctx) 
{
+    return create(name, category, id, phase, start_ts, duration, 
ctx.fragment_instance_id, ctx.task, {});
+}
+
+static const char* kSimpleEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+static const char* kCompleteEventFormat =
+        
R"({"cat":"%s","name":"%s","pid":"0x%x","tid":"0x%x","id":"0x%x","ts":%ld,"dur":%ld,"ph":"%c","args":%s,"tidx":"0x%x"})";
+
+std::string QueryTraceEvent::to_string() {
+    std::string args_str = args_to_string();
+    size_t tidx = std::hash<std::thread::id>{}(thread_id);
+
+    // transform a raw pointer to uint64_t by re_cast is maybe not the best 
way, but at least unambiguous & safe.
+    if (phase == 'X') {
+        return fmt::sprintf(kCompleteEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
duration, phase, args_str.c_str(), tidx);
+    } else {
+        return fmt::sprintf(kSimpleEventFormat, category.c_str(), 
name.c_str(), (uint64_t)instance_id,
+                            reinterpret_cast<uint64_t>(task), id, start_time, 
phase, args_str.c_str(), tidx);
+    }
+}
+
+std::string QueryTraceEvent::args_to_string() {
+    if (args.empty()) {
+        return "{}";
+    }
+    std::ostringstream oss;
+    oss << "{";
+    oss << fmt::sprintf(R"("%s":"%s")", args[0].first.c_str(), 
args[0].second.c_str());
+    for (size_t i = 1; i < args.size(); i++) {
+        oss << fmt::sprintf(R"(,"%s":"%s")", args[i].first.c_str(), 
args[i].second.c_str());
+    }
+    oss << "}";
+    return oss.str();
+}
+
+void EventBuffer::add(QueryTraceEvent&& event) {
+    std::lock_guard<std::mutex> l(_mutex);
+    _buffer.emplace_back(std::move(event));
+}
+
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) : 
_query_id(query_id), _is_enable(is_enable) {
+    if (_is_enable) {
+        _start_ts = MonotonicMicros();
+    }
+}
+#else
+QueryTrace::QueryTrace(const TUniqueId& query_id, bool is_enable) {}
+#endif
+
+void QueryTrace::register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks) {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return;
+    }
+    std::unique_lock l(_mutex);
+    auto iter = _fragment_tasks.find(fragment_instance_id);
+    if (iter == _fragment_tasks.end()) {
+        _fragment_tasks.emplace(fragment_instance_id,
+                                    
std::make_shared<std::unordered_set<pipeline::PipelineTaskRawPtr>>());
+        iter = _fragment_tasks.find(fragment_instance_id);
+    }
+    for (auto& task : tasks) {
+        iter->second->insert(task); // into this fragment's task map.
+        _buffers.emplace(task, std::make_unique<EventBuffer>());
+    }
+#endif
+}
+
+Status QueryTrace::dump() {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!_is_enable) {
+        return Status::OK();
+    }
+    static const char* kProcessNameMetaEventFormat =
+            
"{\"name\":\"process_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    static const char* kThreadNameMetaEventFormat =
+            
"{\"name\":\"thread_name\",\"ph\":\"M\",\"pid\":\"0x%x\",\"tid\":\"0x%x\",\"args\":{\"name\":\"%s\"}}";
+    try {
+        std::filesystem::create_directory(doris::config::tracing_dir);
+        std::string file_name =
+                fmt::format("{}/{}.json", doris::config::tracing_dir, 
print_id(_query_id));
+        std::ofstream oss(file_name.c_str(), std::ios::out | std::ios::binary);
+        oss << "{\"traceEvents\":[\n";
+        bool is_first = true;
+        for (auto& [fragment_id, task_set] : _fragment_tasks) {
+            std::string fragment_id_str = print_id(fragment_id);
+            oss << (is_first ? "" : ",\n");
+            oss << fmt::sprintf(kProcessNameMetaEventFormat, 
(uint64_t)fragment_id.lo, fragment_id_str.c_str());
+            is_first = false;
+            for (auto& task : *task_set) {
+                pipeline::PipelineTaskRawPtr ptr = 
reinterpret_cast<pipeline::PipelineTaskRawPtr>(task);
+                oss << (is_first ? "" : ",\n");
+                oss << fmt::sprintf(kThreadNameMetaEventFormat, 
(uint64_t)fragment_id.lo, reinterpret_cast<uint64_t>(task.get()),
+                                    std::to_string(ptr->get_id()));
+            }
+        }
+
+        for (auto& [_, buffer_ptr] : _buffers) {
+            auto& buffer = buffer_ptr->_buffer;
+            for (auto iter : buffer) {
+                oss << (is_first ? "" : ",\n");
+                oss << iter.to_string();
+            }
+        }
+        oss << "\n]}";
+
+        oss.close();
+    } catch (std::exception& e) {
+        return Status::IOError(fmt::format("dump trace log error {}", 
e.what()));
+    }
+#endif
+    return Status::OK();
+}
+
+void QueryTrace::set_tls_trace_context(QueryTrace* query_trace, const 
TUniqueId& fragment_instance_id,
+                                       pipeline::PipelineTaskRawPtr task) {
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    if (!query_trace->_is_enable) {
+        tls_trace_ctx.reset();
+        return;
+    }
+    {
+        std::shared_lock l(query_trace->_mutex);
+        auto iter = query_trace->_buffers.find(task);

Review Comment:
   warning: no member named '_buffers' in 'doris::debug::QueryTrace' 
[clang-diagnostic-error]
   ```cpp
           auto iter = query_trace->_buffers.find(task);
                                    ^
   ```
   



##########
be/src/util/debug/tracing.h:
##########
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <deque>
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <shared_mutex>
+#include <string>
+#include <unordered_set>
+#include <thread>
+
+#include "common/status.h"
+#include "gen_cpp/Types_types.h"
+#include "pipeline/pipeline_task.h"
+
+#define ENABLE_QUERY_DEBUG_TRACE
+
+// The whole function is control by marco in building. if the function is 
turned off, no entity will be construct.
+// In another word, it's zero-overhead.
+
+namespace doris::debug {
+
+class QueryTraceContext;
+
+/// QueryTraceEvent saves a specific event info.
+class QueryTraceEvent {
+public:
+    std::string name;
+    std::string category;
+    int64_t id; // used for async event
+    char phase; // type of event
+    int64_t start_time;
+    int64_t duration = -1; // used only in compelete event
+    decltype(TUniqueId::lo) instance_id;
+    pipeline::PipelineTaskRawPtr task; // task pointer

Review Comment:
   warning: no type named 'PipelineTaskRawPtr' in namespace 'doris::pipeline' 
[clang-diagnostic-error]
   ```cpp
       pipeline::PipelineTaskRawPtr task; // task pointer
                 ^
   ```
   



##########
be/src/util/debug/tracing.h:
##########
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <deque>
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <shared_mutex>
+#include <string>
+#include <unordered_set>
+#include <thread>
+
+#include "common/status.h"
+#include "gen_cpp/Types_types.h"
+#include "pipeline/pipeline_task.h"
+
+#define ENABLE_QUERY_DEBUG_TRACE
+
+// The whole function is control by marco in building. if the function is 
turned off, no entity will be construct.
+// In another word, it's zero-overhead.
+
+namespace doris::debug {
+
+class QueryTraceContext;
+
+/// QueryTraceEvent saves a specific event info.
+class QueryTraceEvent {
+public:
+    std::string name;
+    std::string category;
+    int64_t id; // used for async event
+    char phase; // type of event
+    int64_t start_time;
+    int64_t duration = -1; // used only in compelete event
+    decltype(TUniqueId::lo) instance_id;
+    pipeline::PipelineTaskRawPtr task; // task pointer
+    std::thread::id thread_id;
+    std::vector<std::pair<std::string, std::string>> args;
+
+    std::string to_string();
+
+    static QueryTraceEvent create(const std::string& name, const std::string& 
category, int64_t id, char phase,
+                                  int64_t timestamp, int64_t duration, int64_t 
instance_id, pipeline::PipelineTaskRawPtr task,

Review Comment:
   warning: no type named 'PipelineTaskRawPtr' in namespace 'doris::pipeline' 
[clang-diagnostic-error]
   ```cpp
                                     int64_t timestamp, int64_t duration, 
int64_t instance_id, pipeline::PipelineTaskRawPtr task,
                                                                                
                         ^
   ```
   



##########
be/src/util/debug/tracing.h:
##########
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <deque>
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <shared_mutex>
+#include <string>
+#include <unordered_set>
+#include <thread>
+
+#include "common/status.h"
+#include "gen_cpp/Types_types.h"
+#include "pipeline/pipeline_task.h"
+
+#define ENABLE_QUERY_DEBUG_TRACE
+
+// The whole function is control by marco in building. if the function is 
turned off, no entity will be construct.
+// In another word, it's zero-overhead.
+
+namespace doris::debug {
+
+class QueryTraceContext;
+
+/// QueryTraceEvent saves a specific event info.
+class QueryTraceEvent {
+public:
+    std::string name;
+    std::string category;
+    int64_t id; // used for async event
+    char phase; // type of event
+    int64_t start_time;
+    int64_t duration = -1; // used only in compelete event
+    decltype(TUniqueId::lo) instance_id;
+    pipeline::PipelineTaskRawPtr task; // task pointer
+    std::thread::id thread_id;
+    std::vector<std::pair<std::string, std::string>> args;
+
+    std::string to_string();
+
+    static QueryTraceEvent create(const std::string& name, const std::string& 
category, int64_t id, char phase,
+                                  int64_t timestamp, int64_t duration, int64_t 
instance_id, pipeline::PipelineTaskRawPtr task,
+                                  std::vector<std::pair<std::string, 
std::string>>&& args);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           const QueryTraceContext& ctx);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           int64_t start_ts, int64_t duration, 
const QueryTraceContext& ctx);
+
+private:
+    std::string args_to_string();
+};
+
+/// Event buffer for a single PipelineTask.
+/// didn't store in threads' own trace_context, but in QueryTrace.
+class EventBuffer {
+public:
+    EventBuffer() = default;
+    ~EventBuffer() = default;
+
+    void add(QueryTraceEvent&& event);
+
+private:
+    friend class QueryTrace;
+    std::mutex _mutex;
+    std::deque<QueryTraceEvent> _buffer;
+};
+
+class QueryTrace {
+public:
+    QueryTrace(const TUniqueId& query_id, bool is_enable);
+    ~QueryTrace() = default;
+
+    // init event buffer for all tasks in a single fragment instance
+    void register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks);
+
+    Status dump();
+
+    static void set_tls_trace_context(QueryTrace* query_trace, const 
TUniqueId& fragment_instance_id,
+                                      pipeline::PipelineTaskRawPtr task);
+
+private:
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    TUniqueId _query_id;
+    [[maybe_unused]] bool _is_enable = false;
+    [[maybe_unused]] int64_t _start_ts = -1;
+
+    std::shared_mutex _mutex;
+    std::unordered_map<pipeline::PipelineTaskRawPtr, 
std::unique_ptr<EventBuffer>> _buffers;

Review Comment:
   warning: no member named 'PipelineTaskRawPtr' in namespace 'doris::pipeline' 
[clang-diagnostic-error]
   ```cpp
       std::unordered_map<pipeline::PipelineTaskRawPtr, 
std::unique_ptr<EventBuffer>> _buffers;
                                    ^
   ```
   



##########
be/src/util/debug/tracing.h:
##########
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <deque>
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <shared_mutex>
+#include <string>
+#include <unordered_set>
+#include <thread>
+
+#include "common/status.h"
+#include "gen_cpp/Types_types.h"
+#include "pipeline/pipeline_task.h"
+
+#define ENABLE_QUERY_DEBUG_TRACE
+
+// The whole function is control by marco in building. if the function is 
turned off, no entity will be construct.
+// In another word, it's zero-overhead.
+
+namespace doris::debug {
+
+class QueryTraceContext;
+
+/// QueryTraceEvent saves a specific event info.
+class QueryTraceEvent {
+public:
+    std::string name;
+    std::string category;
+    int64_t id; // used for async event
+    char phase; // type of event
+    int64_t start_time;
+    int64_t duration = -1; // used only in compelete event
+    decltype(TUniqueId::lo) instance_id;
+    pipeline::PipelineTaskRawPtr task; // task pointer
+    std::thread::id thread_id;
+    std::vector<std::pair<std::string, std::string>> args;
+
+    std::string to_string();
+
+    static QueryTraceEvent create(const std::string& name, const std::string& 
category, int64_t id, char phase,
+                                  int64_t timestamp, int64_t duration, int64_t 
instance_id, pipeline::PipelineTaskRawPtr task,
+                                  std::vector<std::pair<std::string, 
std::string>>&& args);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           const QueryTraceContext& ctx);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           int64_t start_ts, int64_t duration, 
const QueryTraceContext& ctx);
+
+private:
+    std::string args_to_string();
+};
+
+/// Event buffer for a single PipelineTask.
+/// didn't store in threads' own trace_context, but in QueryTrace.
+class EventBuffer {
+public:
+    EventBuffer() = default;
+    ~EventBuffer() = default;
+
+    void add(QueryTraceEvent&& event);
+
+private:
+    friend class QueryTrace;
+    std::mutex _mutex;
+    std::deque<QueryTraceEvent> _buffer;
+};
+
+class QueryTrace {
+public:
+    QueryTrace(const TUniqueId& query_id, bool is_enable);
+    ~QueryTrace() = default;
+
+    // init event buffer for all tasks in a single fragment instance
+    void register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks);
+
+    Status dump();
+
+    static void set_tls_trace_context(QueryTrace* query_trace, const 
TUniqueId& fragment_instance_id,
+                                      pipeline::PipelineTaskRawPtr task);
+
+private:
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    TUniqueId _query_id;
+    [[maybe_unused]] bool _is_enable = false;
+    [[maybe_unused]] int64_t _start_ts = -1;
+
+    std::shared_mutex _mutex;
+    std::unordered_map<pipeline::PipelineTaskRawPtr, 
std::unique_ptr<EventBuffer>> _buffers;
+
+    // fragment_instance_id => task list, it will be used to generate meta 
event
+    // instance_id is in PipelineFragmentContext
+    std::unordered_map<TUniqueId, 
std::shared_ptr<std::unordered_set<pipeline::PipelineTaskRawPtr>>> 
_fragment_tasks;

Review Comment:
   warning: no member named 'PipelineTaskRawPtr' in namespace 'doris::pipeline' 
[clang-diagnostic-error]
   ```cpp
       std::unordered_map<TUniqueId, 
std::shared_ptr<std::unordered_set<pipeline::PipelineTaskRawPtr>>> 
_fragment_tasks;
                                                                                
  ^
   ```
   



##########
be/src/util/debug/tracing.h:
##########
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <deque>
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <shared_mutex>
+#include <string>
+#include <unordered_set>
+#include <thread>
+
+#include "common/status.h"
+#include "gen_cpp/Types_types.h"
+#include "pipeline/pipeline_task.h"
+
+#define ENABLE_QUERY_DEBUG_TRACE
+
+// The whole function is control by marco in building. if the function is 
turned off, no entity will be construct.
+// In another word, it's zero-overhead.
+
+namespace doris::debug {
+
+class QueryTraceContext;
+
+/// QueryTraceEvent saves a specific event info.
+class QueryTraceEvent {
+public:
+    std::string name;
+    std::string category;
+    int64_t id; // used for async event
+    char phase; // type of event
+    int64_t start_time;
+    int64_t duration = -1; // used only in compelete event
+    decltype(TUniqueId::lo) instance_id;
+    pipeline::PipelineTaskRawPtr task; // task pointer
+    std::thread::id thread_id;
+    std::vector<std::pair<std::string, std::string>> args;
+
+    std::string to_string();
+
+    static QueryTraceEvent create(const std::string& name, const std::string& 
category, int64_t id, char phase,
+                                  int64_t timestamp, int64_t duration, int64_t 
instance_id, pipeline::PipelineTaskRawPtr task,
+                                  std::vector<std::pair<std::string, 
std::string>>&& args);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           const QueryTraceContext& ctx);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           int64_t start_ts, int64_t duration, 
const QueryTraceContext& ctx);
+
+private:
+    std::string args_to_string();
+};
+
+/// Event buffer for a single PipelineTask.
+/// didn't store in threads' own trace_context, but in QueryTrace.
+class EventBuffer {
+public:
+    EventBuffer() = default;
+    ~EventBuffer() = default;
+
+    void add(QueryTraceEvent&& event);
+
+private:
+    friend class QueryTrace;
+    std::mutex _mutex;
+    std::deque<QueryTraceEvent> _buffer;
+};
+
+class QueryTrace {
+public:
+    QueryTrace(const TUniqueId& query_id, bool is_enable);
+    ~QueryTrace() = default;
+
+    // init event buffer for all tasks in a single fragment instance
+    void register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks);
+
+    Status dump();
+
+    static void set_tls_trace_context(QueryTrace* query_trace, const 
TUniqueId& fragment_instance_id,
+                                      pipeline::PipelineTaskRawPtr task);
+
+private:
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    TUniqueId _query_id;
+    [[maybe_unused]] bool _is_enable = false;
+    [[maybe_unused]] int64_t _start_ts = -1;
+
+    std::shared_mutex _mutex;
+    std::unordered_map<pipeline::PipelineTaskRawPtr, 
std::unique_ptr<EventBuffer>> _buffers;
+
+    // fragment_instance_id => task list, it will be used to generate meta 
event
+    // instance_id is in PipelineFragmentContext
+    std::unordered_map<TUniqueId, 
std::shared_ptr<std::unordered_set<pipeline::PipelineTaskRawPtr>>> 
_fragment_tasks;
+#endif
+};
+
+class ScopedTracer {
+public:
+    ScopedTracer(std::string name, std::string category);
+    ~ScopedTracer() noexcept;
+
+private:
+    std::string _name;
+    std::string _category;
+    int64_t _start_ts;
+    int64_t _duration = -1;
+};
+
+// the real object is saved in bthread_context, a thread_local ThreadContext 
object.
+class QueryTraceContext {
+public:
+    static constexpr int64_t DEFAULT_EVENT_ID = 0;
+
+    int64_t start_ts = -1;
+    int64_t fragment_instance_id = -1;
+    pipeline::PipelineTaskRawPtr task = nullptr;

Review Comment:
   warning: no type named 'PipelineTaskRawPtr' in namespace 'doris::pipeline' 
[clang-diagnostic-error]
   ```cpp
       pipeline::PipelineTaskRawPtr task = nullptr;
                 ^
   ```
   



##########
be/src/util/debug/tracing.h:
##########
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <deque>
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <shared_mutex>
+#include <string>
+#include <unordered_set>
+#include <thread>
+
+#include "common/status.h"
+#include "gen_cpp/Types_types.h"
+#include "pipeline/pipeline_task.h"
+
+#define ENABLE_QUERY_DEBUG_TRACE
+
+// The whole function is control by marco in building. if the function is 
turned off, no entity will be construct.
+// In another word, it's zero-overhead.
+
+namespace doris::debug {
+
+class QueryTraceContext;
+
+/// QueryTraceEvent saves a specific event info.
+class QueryTraceEvent {
+public:
+    std::string name;
+    std::string category;
+    int64_t id; // used for async event
+    char phase; // type of event
+    int64_t start_time;
+    int64_t duration = -1; // used only in compelete event
+    decltype(TUniqueId::lo) instance_id;
+    pipeline::PipelineTaskRawPtr task; // task pointer
+    std::thread::id thread_id;
+    std::vector<std::pair<std::string, std::string>> args;
+
+    std::string to_string();
+
+    static QueryTraceEvent create(const std::string& name, const std::string& 
category, int64_t id, char phase,
+                                  int64_t timestamp, int64_t duration, int64_t 
instance_id, pipeline::PipelineTaskRawPtr task,
+                                  std::vector<std::pair<std::string, 
std::string>>&& args);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           const QueryTraceContext& ctx);
+
+    static QueryTraceEvent create_with_ctx(const std::string& name, const 
std::string& category, int64_t id, char phase,
+                                           int64_t start_ts, int64_t duration, 
const QueryTraceContext& ctx);
+
+private:
+    std::string args_to_string();
+};
+
+/// Event buffer for a single PipelineTask.
+/// didn't store in threads' own trace_context, but in QueryTrace.
+class EventBuffer {
+public:
+    EventBuffer() = default;
+    ~EventBuffer() = default;
+
+    void add(QueryTraceEvent&& event);
+
+private:
+    friend class QueryTrace;
+    std::mutex _mutex;
+    std::deque<QueryTraceEvent> _buffer;
+};
+
+class QueryTrace {
+public:
+    QueryTrace(const TUniqueId& query_id, bool is_enable);
+    ~QueryTrace() = default;
+
+    // init event buffer for all tasks in a single fragment instance
+    void register_tasks(const TUniqueId& fragment_instance_id, 
pipeline::PipelineTasks& tasks);
+
+    Status dump();
+
+    static void set_tls_trace_context(QueryTrace* query_trace, const 
TUniqueId& fragment_instance_id,
+                                      pipeline::PipelineTaskRawPtr task);
+
+private:
+#ifdef ENABLE_QUERY_DEBUG_TRACE
+    TUniqueId _query_id;
+    [[maybe_unused]] bool _is_enable = false;
+    [[maybe_unused]] int64_t _start_ts = -1;
+
+    std::shared_mutex _mutex;
+    std::unordered_map<pipeline::PipelineTaskRawPtr, 
std::unique_ptr<EventBuffer>> _buffers;

Review Comment:
   warning: expected member name or ';' after declaration specifiers 
[clang-diagnostic-error]
   ```cpp
       std::unordered_map<pipeline::PipelineTaskRawPtr, 
std::unique_ptr<EventBuffer>> _buffers;
                                                                                
    ^
   ```
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to