Skip to content

Commit ba08365

Browse files
committed
2 parents 36b7b16 + 601b4ed commit ba08365

File tree

13 files changed

+444
-7
lines changed

13 files changed

+444
-7
lines changed

resource_detectors/BUILD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ otel_cc_library(
1010
srcs = [
1111
"container_detector.cc",
1212
"container_detector_utils.cc",
13+
"process_detector.cc",
14+
"process_detector_utils.cc",
1315
],
16+
copts = ["-fexceptions"],
1417
deps = [
1518
"//api",
1619
"//resource_detectors:headers",

resource_detectors/CMakeLists.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# Copyright The OpenTelemetry Authors
22
# SPDX-License-Identifier: Apache-2.0
33

4-
add_library(opentelemetry_resource_detectors container_detector_utils.cc
5-
container_detector.cc)
4+
add_library(
5+
opentelemetry_resource_detectors
6+
container_detector_utils.cc container_detector.cc process_detector.cc
7+
process_detector_utils.cc)
68

79
set_target_properties(opentelemetry_resource_detectors
810
PROPERTIES EXPORT_NAME resource_detectors)
@@ -28,7 +30,7 @@ otel_add_component(
2830
PATTERN
2931
"*.h"
3032
PATTERN
31-
"container_detector_utils.h"
33+
"resource_detectors/detail/*"
3234
EXCLUDE)
3335

3436
if(BUILD_TESTING)

resource_detectors/container_detector.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#include "opentelemetry/resource_detectors/container_detector.h"
55
#include "opentelemetry/nostd/variant.h"
6-
#include "opentelemetry/resource_detectors/container_detector_utils.h"
6+
#include "opentelemetry/resource_detectors/detail/container_detector_utils.h"
77
#include "opentelemetry/sdk/resource/resource.h"
88
#include "opentelemetry/sdk/resource/resource_detector.h"
99
#include "opentelemetry/semconv/incubating/container_attributes.h"

resource_detectors/container_detector_utils.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright The OpenTelemetry Authors
22
// SPDX-License-Identifier: Apache-2.0
33

4-
#include "opentelemetry/resource_detectors/container_detector_utils.h"
4+
#include "opentelemetry/resource_detectors/detail/container_detector_utils.h"
55
#include "opentelemetry/nostd/string_view.h"
66

77
#include <fstream>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#pragma once
5+
6+
#include <stdint.h>
7+
#include <string>
8+
9+
#include "opentelemetry/version.h"
10+
11+
OPENTELEMETRY_BEGIN_NAMESPACE
12+
namespace resource_detector
13+
{
14+
namespace detail
15+
{
16+
17+
/**
18+
* Forms a file path for a process type based on the given PID.
19+
* for example - /proc/<pid>/cmdline, /proc/<pid>/exe
20+
*/
21+
std::string FormFilePath(const int32_t &pid, const char *process_type);
22+
23+
/**
24+
* Retrieves the absolute file system path to the executable for a given PID.
25+
* Platform-specific behavior:
26+
* - Windows: Uses OpenProcess() + GetProcessImageFileNameW().
27+
* - Linux/Unix: Reads the /proc/<pid>/exe symbolic link.
28+
* - TODO: Need to implement for Darwin
29+
*
30+
* @param pid Process ID.
31+
*/
32+
std::string GetExecutablePath(const int32_t &pid);
33+
34+
/**
35+
* Retrieves the command used to launch the process for a given PID.
36+
* Platform-specific behavior:
37+
* - Windows: Uses GetCommandLineW() to get the command of the current process.
38+
* - Linux/Unix: Reads the zeroth string of /proc/<pid>/cmdline file.
39+
* - TODO: Need to implement for Darwin
40+
*/
41+
std::string ExtractCommand(const std::string &command_line_path);
42+
43+
/**
44+
* Retrieves the command used to launch the process for a given PID.
45+
* This function is a wrapper around ExtractCommand() and is provided for convenience and
46+
* testability of ExtractCommand().
47+
*/
48+
std::string GetCommand(const int32_t &pid);
49+
50+
} // namespace detail
51+
} // namespace resource_detector
52+
OPENTELEMETRY_END_NAMESPACE
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#pragma once
5+
6+
#include "opentelemetry/sdk/resource/resource.h"
7+
#include "opentelemetry/sdk/resource/resource_detector.h"
8+
#include "opentelemetry/version.h"
9+
10+
OPENTELEMETRY_BEGIN_NAMESPACE
11+
namespace resource_detector
12+
{
13+
14+
/**
15+
* ProcessResourceDetector to detect resource attributes when running in a process.
16+
* This detector extracts metadata such as process ID, executable path, and command line arguments
17+
* and sets attributes like process.pid, process.executable.path, and process.command following
18+
* the OpenTelemetry semantic conventions.
19+
*/
20+
class ProcessResourceDetector : public opentelemetry::sdk::resource::ResourceDetector
21+
{
22+
public:
23+
/**
24+
* Detect retrieves the resource attributes for the current process.
25+
* It reads:
26+
* - process.pid from the current process ID
27+
* - process.executable.path from the executable path of the current process
28+
* - process.command from the command used to launch the process
29+
* and returns a Resource with these attributes set.
30+
*/
31+
opentelemetry::sdk::resource::Resource Detect() noexcept override;
32+
};
33+
34+
} // namespace resource_detector
35+
OPENTELEMETRY_END_NAMESPACE
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#include "opentelemetry/resource_detectors/process_detector.h"
5+
#include "opentelemetry/nostd/variant.h"
6+
#include "opentelemetry/resource_detectors/detail/process_detector_utils.h"
7+
#include "opentelemetry/sdk/common/global_log_handler.h"
8+
#include "opentelemetry/sdk/resource/resource.h"
9+
#include "opentelemetry/sdk/resource/resource_detector.h"
10+
#include "opentelemetry/semconv/incubating/process_attributes.h"
11+
#include "opentelemetry/version.h"
12+
13+
#include <stdint.h>
14+
#include <exception>
15+
#include <ostream>
16+
#include <string>
17+
#include <unordered_map>
18+
#include <utility>
19+
20+
#ifdef _MSC_VER
21+
# include <process.h>
22+
# define getpid _getpid
23+
#else
24+
# include <unistd.h>
25+
#endif
26+
27+
OPENTELEMETRY_BEGIN_NAMESPACE
28+
namespace resource_detector
29+
{
30+
31+
opentelemetry::sdk::resource::Resource ProcessResourceDetector::Detect() noexcept
32+
{
33+
int32_t pid = getpid();
34+
opentelemetry::sdk::resource::ResourceAttributes attributes;
35+
attributes[semconv::process::kProcessPid] = pid;
36+
37+
try
38+
{
39+
std::string executable_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid);
40+
if (!executable_path.empty())
41+
{
42+
attributes[semconv::process::kProcessExecutablePath] = std::move(executable_path);
43+
}
44+
}
45+
catch (const ::std::exception &ex)
46+
{
47+
OTEL_INTERNAL_LOG_ERROR("[Process Resource Detector] "
48+
<< "Error extracting the executable path: " << ex.what());
49+
}
50+
51+
try
52+
{
53+
std::string command = opentelemetry::resource_detector::detail::GetCommand(pid);
54+
if (!command.empty())
55+
{
56+
attributes[semconv::process::kProcessCommand] = std::move(command);
57+
}
58+
}
59+
catch (const std::exception &ex)
60+
{
61+
OTEL_INTERNAL_LOG_ERROR("[Process Resource Detector] " << "Error extracting command: "
62+
<< ex.what());
63+
}
64+
65+
return ResourceDetector::Create(attributes);
66+
}
67+
68+
} // namespace resource_detector
69+
OPENTELEMETRY_END_NAMESPACE
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#include "opentelemetry/resource_detectors/detail/process_detector_utils.h"
5+
6+
#include <fstream>
7+
#include <string>
8+
9+
#ifdef _MSC_VER
10+
// clang-format off
11+
# include <windows.h>
12+
# include <psapi.h>
13+
// clang-format on
14+
#else
15+
# include <sys/types.h>
16+
# include <unistd.h>
17+
# include <cstdio>
18+
#endif
19+
20+
#include "opentelemetry/version.h"
21+
22+
OPENTELEMETRY_BEGIN_NAMESPACE
23+
namespace resource_detector
24+
{
25+
namespace detail
26+
{
27+
28+
constexpr const char *kExecutableName = "exe";
29+
constexpr const char *kCmdlineName = "cmdline";
30+
31+
std::string GetExecutablePath(const int32_t &pid)
32+
{
33+
#ifdef _MSC_VER
34+
HANDLE hProcess =
35+
OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, static_cast<DWORD>(pid));
36+
if (!hProcess)
37+
{
38+
return std::string();
39+
}
40+
41+
WCHAR wbuffer[MAX_PATH];
42+
DWORD len = GetProcessImageFileNameW(hProcess, wbuffer, MAX_PATH);
43+
CloseHandle(hProcess);
44+
45+
if (len == 0)
46+
{
47+
return std::string();
48+
}
49+
50+
// Convert UTF-16 to UTF-8
51+
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, NULL, 0, NULL, NULL);
52+
std::string utf8_path(size_needed, 0);
53+
WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, &utf8_path[0], size_needed, NULL, NULL);
54+
55+
return utf8_path;
56+
#else
57+
std::string path = FormFilePath(pid, kExecutableName);
58+
char buffer[4096];
59+
60+
ssize_t len = readlink(path.c_str(), buffer, sizeof(buffer) - 1);
61+
if (len != -1)
62+
{
63+
buffer[len] = '\0';
64+
return std::string(buffer);
65+
}
66+
67+
return std::string();
68+
#endif
69+
}
70+
71+
std::string GetCommand(const int32_t &pid)
72+
{
73+
#ifdef _MSC_VER
74+
// On Windows, GetCommandLineW only works for the CURRENT process,
75+
// so we ignore `pid` and just return the current process's command line.
76+
LPCWSTR wcmd = GetCommandLineW();
77+
if (!wcmd)
78+
{
79+
return std::string();
80+
}
81+
82+
// Convert UTF-16 to UTF-8
83+
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wcmd, -1, NULL, 0, NULL, NULL);
84+
if (size_needed <= 0)
85+
{
86+
return std::string();
87+
}
88+
89+
std::string utf8_command(size_needed - 1, 0); // exclude null terminator
90+
WideCharToMultiByte(CP_UTF8, 0, wcmd, -1, &utf8_command[0], size_needed, NULL, NULL);
91+
92+
return utf8_command;
93+
#else
94+
// This is the path to get the command that was used to start the process
95+
std::string command_line_path = FormFilePath(pid, kCmdlineName);
96+
return ExtractCommand(command_line_path);
97+
#endif
98+
}
99+
100+
std::string ExtractCommand(const std::string &command_line_path)
101+
{
102+
std::string command;
103+
std::ifstream command_line_file(command_line_path, std::ios::in | std::ios::binary);
104+
std::getline(command_line_file, command, '\0');
105+
return command;
106+
}
107+
108+
std::string FormFilePath(const int32_t &pid, const char *process_type)
109+
{
110+
char buff[64];
111+
int len = std::snprintf(buff, sizeof(buff), "/proc/%d/%s", pid, process_type);
112+
if (len < 0)
113+
{
114+
// in case snprintf fails
115+
return std::string();
116+
}
117+
if (len >= static_cast<int>(sizeof(buff)))
118+
{
119+
return std::string(buff, sizeof(buff) - 1);
120+
}
121+
return std::string(buff, len);
122+
}
123+
124+
} // namespace detail
125+
} // namespace resource_detector
126+
OPENTELEMETRY_END_NAMESPACE

resource_detectors/test/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ otel_cc_test(
88
name = "resource_detector_test",
99
srcs = [
1010
"container_detector_test.cc",
11+
"process_detector_test.cc",
1112
],
1213
tags = ["test"],
1314
deps = dll_deps([

0 commit comments

Comments
 (0)