Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions resource_detectors/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ cc_library(
srcs = [
"container_detector.cc",
"container_detector_utils.cc",
"process_detector.cc",
"process_detector_utils.cc",
],
copts = ["-fexceptions"],
deps = [
"//api",
"//resource_detectors:headers",
Expand Down
8 changes: 5 additions & 3 deletions resource_detectors/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

add_library(opentelemetry_resource_detectors container_detector_utils.cc
container_detector.cc)
add_library(
opentelemetry_resource_detectors
container_detector_utils.cc container_detector.cc process_detector.cc
process_detector_utils.cc)

set_target_properties(opentelemetry_resource_detectors
PROPERTIES EXPORT_NAME resource_detectors)
Expand All @@ -28,7 +30,7 @@ otel_add_component(
PATTERN
"*.h"
PATTERN
"container_detector_utils.h"
"resource_detectors/detail/*"
EXCLUDE)

if(BUILD_TESTING)
Expand Down
2 changes: 1 addition & 1 deletion resource_detectors/container_detector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include "opentelemetry/resource_detectors/container_detector.h"
#include "opentelemetry/nostd/variant.h"
#include "opentelemetry/resource_detectors/container_detector_utils.h"
#include "opentelemetry/resource_detectors/detail/container_detector_utils.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/resource/resource_detector.h"
#include "opentelemetry/semconv/incubating/container_attributes.h"
Expand Down
2 changes: 1 addition & 1 deletion resource_detectors/container_detector_utils.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include "opentelemetry/resource_detectors/container_detector_utils.h"
#include "opentelemetry/resource_detectors/detail/container_detector_utils.h"
#include "opentelemetry/nostd/string_view.h"

#include <fstream>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <stdint.h>
#include <string>

#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace resource_detector
{
namespace detail
{

/**
* Forms a file path for a process type based on the given PID.
* for example - /proc/<pid>/cmdline, /proc/<pid>/exe
*/
std::string FormFilePath(const int32_t &pid, const char *process_type);

/**
* Retrieves the absolute file system path to the executable for a given PID.
* Platform-specific behavior:
* - Windows: Uses OpenProcess() + GetProcessImageFileNameW().
* - Linux/Unix: Reads the /proc/<pid>/exe symbolic link.
* - TODO: Need to implement for Darwin
*
* @param pid Process ID.
*/
std::string GetExecutablePath(const int32_t &pid);

/**
* Retrieves the command used to launch the process for a given PID.
* Platform-specific behavior:
* - Windows: Uses GetCommandLineW() to get the command of the current process.
* - Linux/Unix: Reads the zeroth string of /proc/<pid>/cmdline file.
* - TODO: Need to implement for Darwin
*/
std::string ExtractCommand(const std::string &command_line_path);

/**
* Retrieves the command used to launch the process for a given PID.
* This function is a wrapper around ExtractCommand() and is provided for convenience and
* testability of ExtractCommand().
*/
std::string GetCommand(const int32_t &pid);

} // namespace detail
} // namespace resource_detector
OPENTELEMETRY_END_NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/resource/resource_detector.h"
#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace resource_detector
{

/**
* ProcessResourceDetector to detect resource attributes when running in a process.
* This detector extracts metadata such as process ID, executable path, and command line arguments
* and sets attributes like process.pid, process.executable.path, and process.command following
* the OpenTelemetry semantic conventions.
*/
class ProcessResourceDetector : public opentelemetry::sdk::resource::ResourceDetector
{
public:
/**
* Detect retrieves the resource attributes for the current process.
* It reads:
* - process.pid from the current process ID
* - process.executable.path from the executable path of the current process
* - process.command from the command used to launch the process
* and returns a Resource with these attributes set.
*/
opentelemetry::sdk::resource::Resource Detect() noexcept override;
};

} // namespace resource_detector
OPENTELEMETRY_END_NAMESPACE
69 changes: 69 additions & 0 deletions resource_detectors/process_detector.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include "opentelemetry/resource_detectors/process_detector.h"
#include "opentelemetry/nostd/variant.h"
#include "opentelemetry/resource_detectors/detail/process_detector_utils.h"
#include "opentelemetry/sdk/common/global_log_handler.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/resource/resource_detector.h"
#include "opentelemetry/semconv/incubating/process_attributes.h"
#include "opentelemetry/version.h"

#include <stdint.h>
#include <exception>
#include <ostream>
#include <string>
#include <unordered_map>
#include <utility>

#ifdef _MSC_VER
# include <process.h>
# define getpid _getpid
#else
# include <unistd.h>
#endif

OPENTELEMETRY_BEGIN_NAMESPACE
namespace resource_detector
{

opentelemetry::sdk::resource::Resource ProcessResourceDetector::Detect() noexcept
{
int32_t pid = getpid();
opentelemetry::sdk::resource::ResourceAttributes attributes;
attributes[semconv::process::kProcessPid] = pid;

try
{
std::string executable_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid);
if (!executable_path.empty())
{
attributes[semconv::process::kProcessExecutablePath] = std::move(executable_path);
}
}
catch (const ::std::exception &ex)
{
OTEL_INTERNAL_LOG_ERROR("[Process Resource Detector] "
<< "Error extracting the executable path: " << ex.what());
}

try
{
std::string command = opentelemetry::resource_detector::detail::GetCommand(pid);
if (!command.empty())
{
attributes[semconv::process::kProcessCommand] = std::move(command);
}
}
catch (const std::exception &ex)
{
OTEL_INTERNAL_LOG_ERROR("[Process Resource Detector] " << "Error extracting command: "
<< ex.what());
}

return ResourceDetector::Create(attributes);
}

} // namespace resource_detector
OPENTELEMETRY_END_NAMESPACE
126 changes: 126 additions & 0 deletions resource_detectors/process_detector_utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include "opentelemetry/resource_detectors/detail/process_detector_utils.h"

#include <fstream>
#include <string>

#ifdef _MSC_VER
// clang-format off
# include <windows.h>
# include <psapi.h>
// clang-format on
#else
# include <sys/types.h>
# include <unistd.h>
# include <cstdio>
#endif

#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace resource_detector
{
namespace detail
{

constexpr const char *kExecutableName = "exe";
constexpr const char *kCmdlineName = "cmdline";

std::string GetExecutablePath(const int32_t &pid)
{
#ifdef _MSC_VER
HANDLE hProcess =
OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, static_cast<DWORD>(pid));
if (!hProcess)
{
return std::string();
}

WCHAR wbuffer[MAX_PATH];
DWORD len = GetProcessImageFileNameW(hProcess, wbuffer, MAX_PATH);
CloseHandle(hProcess);

if (len == 0)
{
return std::string();
}

// Convert UTF-16 to UTF-8
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, NULL, 0, NULL, NULL);
std::string utf8_path(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, &utf8_path[0], size_needed, NULL, NULL);

return utf8_path;
#else
std::string path = FormFilePath(pid, kExecutableName);
char buffer[4096];

ssize_t len = readlink(path.c_str(), buffer, sizeof(buffer) - 1);
if (len != -1)
{
buffer[len] = '\0';
return std::string(buffer);
}

return std::string();
#endif
}

std::string GetCommand(const int32_t &pid)
{
#ifdef _MSC_VER
// On Windows, GetCommandLineW only works for the CURRENT process,
// so we ignore `pid` and just return the current process's command line.
LPCWSTR wcmd = GetCommandLineW();
if (!wcmd)
{
return std::string();
}

// Convert UTF-16 to UTF-8
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wcmd, -1, NULL, 0, NULL, NULL);
if (size_needed <= 0)
{
return std::string();
}

std::string utf8_command(size_needed - 1, 0); // exclude null terminator
WideCharToMultiByte(CP_UTF8, 0, wcmd, -1, &utf8_command[0], size_needed, NULL, NULL);

return utf8_command;
#else
// This is the path to get the command that was used to start the process
std::string command_line_path = FormFilePath(pid, kCmdlineName);
return ExtractCommand(command_line_path);
#endif
}

std::string ExtractCommand(const std::string &command_line_path)
{
std::string command;
std::ifstream command_line_file(command_line_path, std::ios::in | std::ios::binary);
std::getline(command_line_file, command, '\0');
return command;
}

std::string FormFilePath(const int32_t &pid, const char *process_type)
{
char buff[64];
int len = std::snprintf(buff, sizeof(buff), "/proc/%d/%s", pid, process_type);
if (len < 0)
{
// in case snprintf fails
return std::string();
}
if (len >= static_cast<int>(sizeof(buff)))
{
return std::string(buff, sizeof(buff) - 1);
}
return std::string(buff, len);
}

} // namespace detail
} // namespace resource_detector
OPENTELEMETRY_END_NAMESPACE
1 change: 1 addition & 0 deletions resource_detectors/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ cc_test(
name = "resource_detector_test",
srcs = [
"container_detector_test.cc",
"process_detector_test.cc",
],
tags = ["test"],
deps = [
Expand Down
3 changes: 2 additions & 1 deletion resource_detectors/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

add_executable(resource_detector_test container_detector_test.cc)
add_executable(resource_detector_test container_detector_test.cc
process_detector_test.cc)

# Link the required dependencies
target_link_libraries(
Expand Down
2 changes: 1 addition & 1 deletion resource_detectors/test/container_detector_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <string>

#include "opentelemetry/nostd/string_view.h"
#include "opentelemetry/resource_detectors/container_detector_utils.h"
#include "opentelemetry/resource_detectors/detail/container_detector_utils.h"

TEST(ContainerIdDetectorTest, ExtractValidContainerIdFromLine)
{
Expand Down
Loading
Loading