Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
66b7a47
link coolbpf libprofiler library
wokron Aug 9, 2025
9255ec2
add CpuProfiler
wokron Aug 9, 2025
003ab81
eBPFDriver support cpu profiling
wokron Aug 9, 2025
ffd9544
add ProcessScanner
wokron Aug 9, 2025
3278f54
PluginOptions alias
wokron Aug 9, 2025
4ced0b5
add CpuProfilingManager
wokron Aug 9, 2025
fc66473
add InputCpuProfiling
wokron Aug 10, 2025
8bf7773
handle invalid regex error
wokron Aug 10, 2025
3c9be18
send profiling event to queue
wokron Aug 12, 2025
00abc94
misc updates
wokron Aug 18, 2025
d322146
add ProcessDiscoveryManager
wokron Aug 18, 2025
00f0377
cpu profiling support multi config
wokron Aug 19, 2025
6dc6ffb
remove old ProcessScanner
wokron Aug 19, 2025
7aae26a
use SetContentNoCopy
wokron Aug 19, 2025
b4567bb
handle regex exception
wokron Aug 19, 2025
0fce248
remove unnecessary set to vector conversion
wokron Aug 19, 2025
1dcdf84
cpu profiling add metrics
wokron Aug 19, 2025
117fb16
EBPFServerUnittest add cpu profiling
wokron Aug 19, 2025
9fb1944
add container discovery options
wokron Aug 19, 2025
47647bb
update cmake in ebpf driver
wokron Aug 20, 2025
4a9a3d9
ListAllProcesses use ProcParser
wokron Aug 20, 2025
b53af84
process discovery support container id
wokron Aug 20, 2025
e5c6394
update container config in process discovery
wokron Aug 20, 2025
55ed93e
fix unused
wokron Aug 20, 2025
02815c9
update eBPFDriver
wokron Aug 25, 2025
bc102f3
support libprofiler set_host_root_path
wokron Sep 16, 2025
03b8f8c
fix parseStackCnt
wokron Sep 16, 2025
5c872a5
cpu profiling event set timestamp
wokron Sep 16, 2025
6bbf483
update config parse logic
wokron Sep 16, 2025
73835e9
add CpuProfilingManagerUnittest
wokron Sep 16, 2025
63d3fa3
refactor AddOrUpdateDiscovery
wokron Sep 16, 2025
2d5012d
fix build failure
wokron Sep 17, 2025
4ddffcd
support trace_id
wokron Oct 20, 2025
1da6133
add livetrace_enable_tracing
wokron Oct 20, 2025
89d817a
update coolbpf commit
wokron Nov 6, 2025
6dcd20e
update build deps
wokron Nov 6, 2025
483f99e
fix build
wokron Nov 6, 2025
a3a8e56
disable container match
wokron Nov 7, 2025
89a8a42
format code
wokron Nov 7, 2025
f747902
ContainerManager add handler
wokron Nov 11, 2025
ddbb811
cpu profiling resupport container discovery
wokron Nov 11, 2025
36fc723
fix
wokron Nov 13, 2025
eac57c4
remove unused code
wokron Nov 13, 2025
f4dca49
use arms format
wokron Nov 14, 2025
af35349
fix
wokron Nov 14, 2025
849879b
remove hard code
wokron Nov 26, 2025
8c95ef4
custom app name
wokron Nov 26, 2025
f47ff0e
add language config
wokron Nov 27, 2025
ce4e86a
replace hard code key
wokron Nov 27, 2025
1b6947e
use NoCopy
wokron Nov 27, 2025
0f58800
fix name
wokron Nov 27, 2025
8a0327a
format code
wokron Nov 28, 2025
644f3ba
support collect interval
wokron Dec 10, 2025
dc311ee
support build libprofiler
wokron Dec 18, 2025
0326171
Merge branch 'main' into support-coolbpf-cpu-profiling
wokron Dec 18, 2025
6c51221
try fix build
wokron Dec 18, 2025
e07dbc3
Merge branch 'main' into support-coolbpf-cpu-profiling
wokron Dec 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ if (LINUX)
if (ENABLE_ENTERPRISE)
set(SUB_DIRECTORIES_LIST ${SUB_DIRECTORIES_LIST} shennong shennong/sdk apm/forward)
endif()
set(SUB_DIRECTORIES_LIST ${SUB_DIRECTORIES_LIST} ebpf ebpf/type ebpf/type/table ebpf/util ebpf/util/sampler ebpf/protocol/http ebpf/protocol/mysql ebpf/protocol ebpf/plugin/file_security ebpf/plugin/network_observer ebpf/plugin/process_security ebpf/plugin/network_security ebpf/plugin ebpf/observer ebpf/security
set(SUB_DIRECTORIES_LIST ${SUB_DIRECTORIES_LIST} ebpf ebpf/type ebpf/type/table ebpf/util ebpf/util/sampler ebpf/protocol/http ebpf/protocol/mysql ebpf/protocol ebpf/plugin/file_security ebpf/plugin/network_observer ebpf/plugin/process_security ebpf/plugin/network_security ebpf/plugin/cpu_profiling ebpf/plugin ebpf/observer ebpf/security
prometheus prometheus/labels prometheus/schedulers prometheus/async prometheus/component
host_monitor host_monitor/collector host_monitor/common forward forward/loongsuite
)
Expand Down
2 changes: 1 addition & 1 deletion core/_thirdparty/coolbpf
Submodule coolbpf updated from bc2e5e to 111b2f
1 change: 1 addition & 0 deletions core/app_config/AppConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ class AppConfig {
friend class PollingPreservedDirDepthUnittest;
friend class InputStaticFileUnittest;
friend class LogInputReaderUnittest;
friend class eBPFServerUnittest;
#endif
};

Expand Down
5 changes: 5 additions & 0 deletions core/collection_pipeline/plugin/PluginRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "plugin/flusher/kafka/FlusherKafka.h"
#endif
#if defined(__linux__) && !defined(__ANDROID__)
#include "plugin/input/InputCpuProfiling.h"
#include "plugin/input/InputFileSecurity.h"
#include "plugin/input/InputHostMeta.h"
#include "plugin/input/InputHostMonitor.h"
Expand All @@ -78,6 +79,7 @@ DEFINE_FLAG_BOOL(enable_ebpf_network_observer, "", true);
DEFINE_FLAG_BOOL(enable_ebpf_process_secure, "", true);
DEFINE_FLAG_BOOL(enable_ebpf_file_secure, "", true);
DEFINE_FLAG_BOOL(enable_ebpf_network_secure, "", false);
DEFINE_FLAG_BOOL(enable_ebpf_cpu_profiling, "", false);

using namespace std;

Expand Down Expand Up @@ -174,6 +176,9 @@ void PluginRegistry::LoadStaticPlugins() {
if (BOOL_FLAG(enable_ebpf_network_secure)) {
RegisterContinuousInputCreator(new StaticInputCreator<InputNetworkSecurity>(), true);
}
if (BOOL_FLAG(enable_ebpf_cpu_profiling)) {
RegisterContinuousInputCreator(new StaticInputCreator<InputCpuProfiling>(), false);
}
RegisterContinuousInputCreator(new StaticInputCreator<InputHostMeta>(), true);
RegisterContinuousInputCreator(new StaticInputCreator<InputHostMonitor>(), true);
RegisterContinuousInputCreator(new StaticInputCreator<InputForward>());
Expand Down
52 changes: 49 additions & 3 deletions core/container_manager/ContainerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,21 @@ void ContainerManager::ApplyContainerDiffs() {
auto nameConfigMap = FileServer::GetInstance()->GetAllFileDiscoveryConfigs();
std::vector<std::shared_ptr<MatchedContainerInfo>> configResults;
for (auto& pair : mConfigContainerDiffMap) {
FileDiscoveryOptions* options = nullptr;
const CollectionPipelineContext* ctx = nullptr;
const auto& itr = nameConfigMap.find(pair.first);
if (itr == nameConfigMap.end()) {
continue;
std::lock_guard<std::mutex> lock(mContainerHandlersMutex);
const auto& handlerItr = mContainerHandlers.find(pair.first);
if (handlerItr == mContainerHandlers.end()) {
continue;
}
options = handlerItr->second.first.first;
ctx = handlerItr->second.first.second;
} else {
options = itr->second.first;
ctx = itr->second.second;
}
const auto& options = itr->second.first;
const auto& ctx = itr->second.second;

const auto& diff = pair.second;

Expand Down Expand Up @@ -206,6 +215,20 @@ bool ContainerManager::CheckContainerDiffForAllConfig() {
}
}
}
{
std::lock_guard<std::mutex> lock(mContainerHandlersMutex);
for (auto itr = mContainerHandlers.begin(); itr != mContainerHandlers.end(); ++itr) {
FileDiscoveryOptions* options = itr->second.first.first;
if (options->IsContainerDiscoveryEnabled()) {
bool isCurrentConfigUpdate = checkContainerDiffForOneConfig(options, itr->second.first.second);
if (isCurrentConfigUpdate) {
isUpdate = true;
// Invoke callback
itr->second.second(mConfigContainerDiffMap[itr->first]);
}
}
}
}
return isUpdate;
}

Expand Down Expand Up @@ -270,6 +293,17 @@ void ContainerManager::sendMatchedContainerInfo(std::vector<std::shared_ptr<Matc
}
}

void ContainerManager::AddContainerHandler(const std::string& name,
const FileDiscoveryConfig& config,
const std::function<void(std::shared_ptr<ContainerDiff>)>& handler) {
std::lock_guard<std::mutex> lock(mContainerHandlersMutex);
mContainerHandlers[name] = std::make_pair(config, handler);
}

void ContainerManager::RemoveContainerHandler(const std::string& name) {
std::lock_guard<std::mutex> lock(mContainerHandlersMutex);
mContainerHandlers.erase(name);
}

bool ContainerManager::checkContainerDiffForOneConfig(FileDiscoveryOptions* options,
const CollectionPipelineContext* ctx) {
Expand Down Expand Up @@ -1033,6 +1067,18 @@ void ContainerManager::loadContainerInfoFromContainersFormat(const Json::Value&
checkContainerDiffForOneConfig(options, itr->second.second);
}
}
{
std::lock_guard<std::mutex> lock(mContainerHandlersMutex);
for (auto iter = mContainerHandlers.begin(); iter != mContainerHandlers.end(); ++iter) {
FileDiscoveryOptions* options = iter->second.first.first;
if (options->IsContainerDiscoveryEnabled()) {
if (checkContainerDiffForOneConfig(options, nullptr)) {
// Invoke callback
iter->second.second(mConfigContainerDiffMap[iter->first]);
}
}
}
}
LOG_INFO(sLogger, ("load container state from docker_path_config.json (v1.0.0)", configPath));
}
}
Expand Down
9 changes: 9 additions & 0 deletions core/container_manager/ContainerManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ class ContainerManager {
void UpdateMatchedContainerInfoPipeline(CollectionPipelineContext* ctx, size_t inputIndex);
void RemoveMatchedContainerInfoPipeline();

void AddContainerHandler(const std::string& name,
const FileDiscoveryConfig& config,
const std::function<void(std::shared_ptr<ContainerDiff>)>& handler);
void RemoveContainerHandler(const std::string& name);

private:
void pollingLoop();
void refreshAllContainersSnapshot();
Expand Down Expand Up @@ -101,6 +106,10 @@ class ContainerManager {
mutable ReadWriteLock mMatchedContainerInfoPipelineMux;
CollectionPipelineContext* mMatchedContainerInfoPipelineCtx = nullptr;
size_t mMatchedContainerInfoInputIndex = 0;

std::mutex mContainerHandlersMutex;
using ContainerHandler = std::pair<FileDiscoveryConfig, std::function<void(std::shared_ptr<ContainerDiff>)>>;
std::unordered_map<std::string, ContainerHandler> mContainerHandlers;
};

} // namespace logtail
59 changes: 59 additions & 0 deletions core/ebpf/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <string>
#include <unordered_set>

#include "app_config/AppConfig.h"
#include "common/Flags.h"
#include "common/ParamExtractor.h"
#include "logger/Logger.h"
Expand Down Expand Up @@ -555,6 +556,64 @@ bool SecurityOptions::Init(SecurityProbeType probeType,
return true;
}

bool CpuProfilingOption::Init(const Json::Value& config,
const CollectionPipelineContext* mContext,
const std::string& sName) {
std::string errorMsg;

if (!GetOptionalUIntParam(config, "CollectIntervalMs", mCollectIntervalMs, errorMsg)) {
PARAM_WARNING_IGNORE(mContext->GetLogger(),
mContext->GetAlarm(),
errorMsg,
sName,
mContext->GetConfigName(),
mContext->GetProjectName(),
mContext->GetLogstoreName(),
mContext->GetRegion());
}

if (!GetOptionalStringParam(config, "AppName", mAppName, errorMsg)) {
PARAM_WARNING_IGNORE(mContext->GetLogger(),
mContext->GetAlarm(),
errorMsg,
sName,
mContext->GetConfigName(),
mContext->GetProjectName(),
mContext->GetLogstoreName(),
mContext->GetRegion());
}

if (!GetOptionalStringParam(config, "Language", mLanguage, errorMsg)) {
PARAM_WARNING_IGNORE(mContext->GetLogger(),
mContext->GetAlarm(),
errorMsg,
sName,
mContext->GetConfigName(),
mContext->GetProjectName(),
mContext->GetLogstoreName(),
mContext->GetRegion());
}

if (!GetOptionalListFilterParam<std::string>(config, "CommandLines", mCmdlines, errorMsg)) {
PARAM_WARNING_IGNORE(mContext->GetLogger(),
mContext->GetAlarm(),
errorMsg,
sName,
mContext->GetConfigName(),
mContext->GetProjectName(),
mContext->GetLogstoreName(),
mContext->GetRegion());
}

if (AppConfig::GetInstance()->IsPurageContainerMode()) {
if (!mContainerDiscovery.Init(config, *mContext, sName)) {
return false;
}
}

return true;
}

//////
void eBPFAdminConfig::LoadEbpfConfig(const Json::Value& confJson) {
// receive_event_chan_cap (Optional)
Expand Down
18 changes: 18 additions & 0 deletions core/ebpf/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "json/json.h"

#include "collection_pipeline/CollectionPipelineContext.h"
#include "container_manager/ContainerDiscoveryOptions.h"
#include "ebpf/include/export.h"

namespace logtail::ebpf {
Expand Down Expand Up @@ -48,6 +49,23 @@ class SecurityOptions {
SecurityProbeType mProbeType;
};

///////////////////// /////////////////////

class CpuProfilingOption {
public:
bool Init(const Json::Value& config, const CollectionPipelineContext* mContext, const std::string& sName);

uint32_t mCollectIntervalMs = 0; // 0 means use default
std::vector<std::string> mCmdlines;
std::string mAppName;
// Since ebpf may collect mulit-language profiling data,
// the language field should be set by user.
std::string mLanguage = "java";
ContainerDiscoveryOptions mContainerDiscovery;
};

using PluginOptions = std::variant<SecurityOptions*, ObserverNetworkOption*, CpuProfilingOption*>;

///////////////////// Process Level Config /////////////////////

struct AdminConfig {
Expand Down
43 changes: 30 additions & 13 deletions core/ebpf/EBPFServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "ebpf/plugin/AbstractManager.h"
#include "logger/Logger.h"
#include "monitor/metric_models/ReentrantMetricsRecord.h"
#include "plugin/cpu_profiling/CpuProfilingManager.h"
#include "plugin/file_security/FileSecurityManager.h"
#include "plugin/network_observer/NetworkObserverManager.h"
#include "plugin/network_security/NetworkSecurityManager.h"
Expand Down Expand Up @@ -59,7 +60,8 @@ bool EnvManager::IsSupportedEnv(PluginType type) {
break;
case PluginType::FILE_SECURITY:
case PluginType::NETWORK_SECURITY:
case PluginType::PROCESS_SECURITY: {
case PluginType::PROCESS_SECURITY:
case PluginType::CPU_PROFILING: {
status = mArchSupport && mBTFSupport;
break;
}
Expand Down Expand Up @@ -282,10 +284,10 @@ bool EBPFServer::startPluginInternal(const std::string& pipelineName,
uint32_t pluginIndex,
PluginType type,
const logtail::CollectionPipelineContext* ctx,
const std::variant<SecurityOptions*, ObserverNetworkOption*>& options,
const PluginOptions& options,
const PluginMetricManagerPtr& metricManager) {
bool isNeedProcessCache = false;
if (type != PluginType::NETWORK_OBSERVE) {
if (type != PluginType::NETWORK_OBSERVE && type != PluginType::CPU_PROFILING) {
isNeedProcessCache = true;
}
auto& pluginMgr = getPluginState(type).mManager;
Expand Down Expand Up @@ -346,6 +348,17 @@ bool EBPFServer::startPluginInternal(const std::string& pipelineName,
}
break;
}

case PluginType::CPU_PROFILING: {
if (!pluginMgr) {
auto mgr = CpuProfilingManager::Create(
mProcessCacheManager, mEBPFAdapter, mCommonEventQueue, &mEventPool);
mgr->SetMetrics(mRecvKernelEventsTotal);
pluginMgr = mgr;
}
break;
}

default:
LOG_ERROR(sLogger, ("Unknown plugin type", int(type)));
return false;
Expand All @@ -371,7 +384,8 @@ bool EBPFServer::startPluginInternal(const std::string& pipelineName,
}

updatePluginState(type, pipelineName, ctx->GetProjectName(), PluginStateOperation::kAddPipeline, pluginMgr);
if (type != PluginType::PROCESS_SECURITY && type != PluginType::NETWORK_OBSERVE) {
if (type != PluginType::PROCESS_SECURITY && type != PluginType::NETWORK_OBSERVE
&& type != PluginType::CPU_PROFILING) {
RegisterPluginPerfBuffers(type);
}

Expand All @@ -391,7 +405,7 @@ bool EBPFServer::EnablePlugin(const std::string& pipelineName,
uint32_t pluginIndex,
PluginType type,
const CollectionPipelineContext* ctx,
const std::variant<SecurityOptions*, ObserverNetworkOption*>& options,
const PluginOptions& options,
const PluginMetricManagerPtr& mgr) {
if (!IsSupportedEnv(type)) {
return false;
Expand Down Expand Up @@ -550,14 +564,17 @@ void EBPFServer::pollPerfBuffers() {
mProcessCacheManager->ClearProcessExpiredCache();

// TODO (@qianlu.kk) adapt to ConsumePerfBufferData
auto& pluginState = getPluginState(PluginType::NETWORK_OBSERVE);
if (!pluginState.mValid.load(std::memory_order_acquire)) {
continue;
}
std::shared_lock<std::shared_mutex> lock(pluginState.mMtx);
if (pluginState.mManager) {
auto* mgr = static_cast<NetworkObserverManager*>(pluginState.mManager.get());
mgr->PollPerfBuffer(0); // 0 means non-blocking r(ef: https://libbpf.readthedocs.io/en/latest/api.html)
std::vector<PluginState*> pluginStatePtrs
= {&getPluginState(PluginType::NETWORK_OBSERVE), &getPluginState(PluginType::CPU_PROFILING)};
for (auto& pluginStatePtr : pluginStatePtrs) {
auto& pluginState = *pluginStatePtr;
if (!pluginState.mValid.load(std::memory_order_acquire)) {
continue;
}
std::shared_lock<std::shared_mutex> lock(pluginState.mMtx);
if (pluginState.mManager) {
pluginState.mManager->PollPerfBuffer(0); // 0 means non-blocking
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/ebpf/EBPFServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class EBPFServer : public InputRunner {
uint32_t pluginIndex,
PluginType type,
const logtail::CollectionPipelineContext* ctx,
const std::variant<SecurityOptions*, ObserverNetworkOption*>& options,
const PluginOptions& options,
const PluginMetricManagerPtr& mgr);

bool DisablePlugin(const std::string& pipelineName, PluginType type);
Expand All @@ -118,7 +118,7 @@ class EBPFServer : public InputRunner {
uint32_t pluginIndex,
PluginType type,
const logtail::CollectionPipelineContext* ctx,
const std::variant<SecurityOptions*, ObserverNetworkOption*>& options,
const PluginOptions& options,
const PluginMetricManagerPtr& metricManager);
EBPFServer();

Expand Down
Loading
Loading