From b717fd5bd5ca783a2f1c3564c31e46cfaee3e2b2 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Sat, 15 Aug 2026 16:43:56 +0530 Subject: [PATCH 01/24] Declare new functions --- .../detail/process_detector_utils.h | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h index 4cd6a12382..79b02c1a75 100644 --- a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h +++ b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h @@ -32,6 +32,15 @@ std::string FormFilePath(const int32_t &pid, const char *process_type); */ std::string GetExecutablePath(const int32_t &pid); +/** + * Returns the base name (filename) of the process executable. + * Derived from GetExecutablePath() by stripping the directory components. + * Platform-specific behavior mirrors GetExecutablePath(). + * + * @param pid Process ID. + */ +std::string GetExecutableName(const int32_t &pid); + /** * Extracts the command-line arguments and the command. * Platform-specific behavior: @@ -48,6 +57,39 @@ std::vector ExtractCommandWithArgs(const std::string &command_line_ */ std::vector GetCommandWithArgs(const int32_t &pid); +/** + * Retrieves the process creation time as an ISO 8601 string (e.g. "2023-11-21T09:25:34.853Z"). + * Platform-specific behavior: + * - Linux: Reads starttime from /proc//stat and combines with boot time. + * - macOS: Uses sysctl(KERN_PROC) to obtain kinfo_proc.kp_proc.p_starttime. + * - Windows: Uses GetProcessTimes() to obtain lpCreationTime (FILETIME). + * Returns an empty string if the information is unavailable. + * + * @param pid Process ID. + */ +std::string GetProcessCreationTime(const int32_t &pid); + +/** + * Retrieves the username of the user that owns the process. + * Platform-specific behavior: + * - Linux/macOS: Uses getuid() + getpwuid_r() to resolve the effective user name. + * - Windows: Uses OpenProcessToken() + GetTokenInformation() + LookupAccountSidW(). + * Returns an empty string if the information is unavailable. + * + * @param pid Process ID. + */ +std::string GetProcessOwner(const int32_t &pid); + +/** + * Computes the deterministic htlhash build ID for the process executable. + * Algorithm: SHA256(File[:4096] || File[-4096:] || BigEndianUInt64(FileLen)) + * The result is the first 16 bytes (128 bits) of the digest as a lowercase hex string. + * Returns an empty string if the executable cannot be read. + * + * @param pid Process ID. + */ +std::string GetExecutableBuildIdHtlhash(const int32_t &pid); + } // namespace detail } // namespace resource_detector OPENTELEMETRY_END_NAMESPACE From dba5977e985195f18ae92f59b56ded9b941dcadb Mon Sep 17 00:00:00 2001 From: Pradeep Date: Sat, 15 Aug 2026 16:46:32 +0530 Subject: [PATCH 02/24] Implementation of platform specific functions --- .../src/process_detector_utils.cc | 466 ++++++++++++++++++ 1 file changed, 466 insertions(+) diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 9da40a52a8..b2e61f224b 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -71,6 +71,22 @@ std::string GetExecutablePath(const int32_t &pid) #endif } +std::string GetExecutableName(const int32_t &pid) +{ + std::string path = GetExecutablePath(pid); + if (path.empty()) + { + return std::string(); + } + // Find last path separator (works for both '/' and '\'). + std::size_t sep = path.find_last_of("/\\"); + if (sep == std::string::npos) + { + return path; + } + return path.substr(sep + 1); +} + std::vector ExtractCommandWithArgs(const std::string &command_line_path) { std::vector commands; @@ -133,6 +149,456 @@ std::string FormFilePath(const int32_t &pid, const char *process_type) return std::string(buff, len); } +// --------------------------------------------------------------------------- +// GetProcessCreationTime +// --------------------------------------------------------------------------- + +#ifdef _MSC_VER +namespace +{ +// Convert a FILETIME to an ISO 8601 UTC string "YYYY-MM-DDTHH:MM:SS.mmmZ". +std::string FileTimeToIso8601(const FILETIME &ft) +{ + SYSTEMTIME st; + if (!FileTimeToSystemTime(&ft, &st)) + { + return std::string(); + } + char buf[32]; + std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + static_cast(st.wYear), static_cast(st.wMonth), + static_cast(st.wDay), static_cast(st.wHour), + static_cast(st.wMinute), static_cast(st.wSecond), + static_cast(st.wMilliseconds)); + return std::string(buf); +} +} // namespace +#endif // _MSC_VER + +#if !defined(_MSC_VER) && !defined(__APPLE__) +namespace +{ +// Parse the 22nd field (starttime, in clock ticks since boot) from /proc//stat. +// The comm field (2nd) may contain spaces/parens, so we scan past the closing ')'. +bool ParseStarttimeFromProcStat(const std::string &stat_path, unsigned long long &starttime_ticks) +{ + std::ifstream f(stat_path); + if (!f.is_open()) + { + return false; + } + std::string line; + if (!std::getline(f, line)) + { + return false; + } + // Skip past the closing ')' of the comm field. + std::size_t pos = line.rfind(')'); + if (pos == std::string::npos) + { + return false; + } + pos += 2; // skip ') ' + // Fields 3..21 (19 fields) come before starttime (field 22, 0-indexed from 3 → index 19). + for (int i = 0; i < 19; ++i) + { + pos = line.find(' ', pos); + if (pos == std::string::npos) + { + return false; + } + ++pos; + } + starttime_ticks = std::stoull(line.substr(pos)); + return true; +} + +// Read boot time in seconds since epoch from /proc/stat. +bool ReadBootTimeSecs(unsigned long long &boot_time) +{ + std::ifstream f("/proc/stat"); + if (!f.is_open()) + { + return false; + } + std::string line; + while (std::getline(f, line)) + { + if (line.substr(0, 6) == "btime ") + { + boot_time = std::stoull(line.substr(6)); + return true; + } + } + return false; +} +} // namespace +#endif // !_MSC_VER && !__APPLE__ + +#ifdef __APPLE__ +# include +#endif + +std::string GetProcessCreationTime(const int32_t &pid) +{ +#ifdef _MSC_VER + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, static_cast(pid)); + if (!hProcess) + { + return std::string(); + } + FILETIME creation_time, exit_time, kernel_time, user_time; + bool ok = GetProcessTimes(hProcess, &creation_time, &exit_time, &kernel_time, &user_time) != 0; + CloseHandle(hProcess); + if (!ok) + { + return std::string(); + } + return FileTimeToIso8601(creation_time); + +#elif defined(__APPLE__) + struct kinfo_proc kp; + std::size_t len = sizeof(kp); + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, static_cast(pid)}; + if (sysctl(mib, 4, &kp, &len, nullptr, 0) != 0 || len == 0) + { + return std::string(); + } + // kp_proc.p_starttime is a struct timeval (seconds + microseconds). + time_t secs = kp.kp_proc.p_starttime.tv_sec; + long usecs = kp.kp_proc.p_starttime.tv_usec; + struct tm utc_time = {}; + gmtime_r(&secs, &utc_time); + char buf[32]; + std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03ldZ", + utc_time.tm_year + 1900, utc_time.tm_mon + 1, utc_time.tm_mday, + utc_time.tm_hour, utc_time.tm_min, utc_time.tm_sec, usecs / 1000); + return std::string(buf); + +#else + // Linux: starttime (ticks since boot) from /proc//stat + btime from /proc/stat. + unsigned long long starttime_ticks = 0; + unsigned long long boot_time_secs = 0; + + std::string stat_path = FormFilePath(pid, "stat"); + if (!ParseStarttimeFromProcStat(stat_path, starttime_ticks)) + { + return std::string(); + } + if (!ReadBootTimeSecs(boot_time_secs)) + { + return std::string(); + } + + long clk_tck = sysconf(_SC_CLK_TCK); + if (clk_tck <= 0) + { + return std::string(); + } + + const auto clk = static_cast(clk_tck); + unsigned long long start_secs = boot_time_secs + starttime_ticks / clk; + unsigned long long start_msecs = (starttime_ticks % clk) * 1000 / clk; + + time_t t = static_cast(start_secs); + struct tm utc_time = {}; + gmtime_r(&t, &utc_time); + + char buf[32]; + std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03lluZ", + utc_time.tm_year + 1900, utc_time.tm_mon + 1, utc_time.tm_mday, + utc_time.tm_hour, utc_time.tm_min, utc_time.tm_sec, start_msecs); + return std::string(buf); +#endif +} + +// --------------------------------------------------------------------------- +// GetProcessOwner +// --------------------------------------------------------------------------- + +#ifndef _MSC_VER +# include +#endif + +std::string GetProcessOwner(const int32_t & /* pid */) +{ +#ifdef _MSC_VER + // On Windows, open the current process token and look up the account SID. + HANDLE hToken = nullptr; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) + { + return std::string(); + } + + DWORD token_info_len = 0; + GetTokenInformation(hToken, TokenUser, nullptr, 0, &token_info_len); + if (token_info_len == 0) + { + CloseHandle(hToken); + return std::string(); + } + + std::vector token_info_buf(token_info_len); + if (!GetTokenInformation(hToken, TokenUser, token_info_buf.data(), token_info_len, + &token_info_len)) + { + CloseHandle(hToken); + return std::string(); + } + CloseHandle(hToken); + + TOKEN_USER *token_user = reinterpret_cast(token_info_buf.data()); + WCHAR name[256]; + WCHAR domain[256]; + DWORD name_len = 256; + DWORD domain_len = 256; + SID_NAME_USE sid_use; + if (!LookupAccountSidW(nullptr, token_user->User.Sid, name, &name_len, domain, &domain_len, + &sid_use)) + { + return std::string(); + } + + // Convert UTF-16 username to UTF-8. + int size_needed = WideCharToMultiByte(CP_UTF8, 0, name, -1, nullptr, 0, nullptr, nullptr); + if (size_needed <= 0) + { + return std::string(); + } + std::string utf8_name(size_needed - 1, '\0'); + WideCharToMultiByte(CP_UTF8, 0, name, -1, &utf8_name[0], size_needed, nullptr, nullptr); + return utf8_name; + +#else + // POSIX (Linux + macOS): resolve effective UID to a username via getpwuid_r. + uid_t uid = getuid(); + struct passwd pw = {}; + struct passwd *result = nullptr; + char buf[1024]; + if (getpwuid_r(uid, &pw, buf, sizeof(buf), &result) != 0 || result == nullptr) + { + return std::string(); + } + return std::string(result->pw_name); +#endif +} + +// --------------------------------------------------------------------------- +// GetExecutableBuildIdHtlhash (self-contained SHA-256, no external deps) +// --------------------------------------------------------------------------- + +namespace +{ + +// Minimal self-contained SHA-256 implementation. +// Reference: FIPS 180-4 +struct Sha256Context +{ + uint32_t state[8]; + uint64_t bit_count; + uint8_t buffer[64]; + uint32_t buffer_len; +}; + +static const uint32_t kSha256K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, + 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, + 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, + 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, + 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, + 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, + 0xc67178f2}; + +inline uint32_t Rotr32(uint32_t x, int n) +{ + return (x >> n) | (x << (32 - n)); +} + +void Sha256ProcessBlock(Sha256Context &ctx, const uint8_t block[64]) +{ + uint32_t w[64]; + for (int i = 0; i < 16; ++i) + { + w[i] = (static_cast(block[i * 4]) << 24) | + (static_cast(block[i * 4 + 1]) << 16) | + (static_cast(block[i * 4 + 2]) << 8) | + (static_cast(block[i * 4 + 3])); + } + for (int i = 16; i < 64; ++i) + { + uint32_t s0 = Rotr32(w[i - 15], 7) ^ Rotr32(w[i - 15], 18) ^ (w[i - 15] >> 3); + uint32_t s1 = Rotr32(w[i - 2], 17) ^ Rotr32(w[i - 2], 19) ^ (w[i - 2] >> 10); + w[i] = w[i - 16] + s0 + w[i - 7] + s1; + } + + uint32_t a = ctx.state[0], b = ctx.state[1], c = ctx.state[2], d = ctx.state[3]; + uint32_t e = ctx.state[4], f = ctx.state[5], g = ctx.state[6], h = ctx.state[7]; + + for (int i = 0; i < 64; ++i) + { + uint32_t S1 = Rotr32(e, 6) ^ Rotr32(e, 11) ^ Rotr32(e, 25); + uint32_t ch = (e & f) ^ (~e & g); + uint32_t temp1 = h + S1 + ch + kSha256K[i] + w[i]; + uint32_t S0 = Rotr32(a, 2) ^ Rotr32(a, 13) ^ Rotr32(a, 22); + uint32_t maj = (a & b) ^ (a & c) ^ (b & c); + uint32_t temp2 = S0 + maj; + + h = g; + g = f; + f = e; + e = d + temp1; + d = c; + c = b; + b = a; + a = temp1 + temp2; + } + + ctx.state[0] += a; + ctx.state[1] += b; + ctx.state[2] += c; + ctx.state[3] += d; + ctx.state[4] += e; + ctx.state[5] += f; + ctx.state[6] += g; + ctx.state[7] += h; +} + +void Sha256Init(Sha256Context &ctx) +{ + ctx.state[0] = 0x6a09e667; + ctx.state[1] = 0xbb67ae85; + ctx.state[2] = 0x3c6ef372; + ctx.state[3] = 0xa54ff53a; + ctx.state[4] = 0x510e527f; + ctx.state[5] = 0x9b05688c; + ctx.state[6] = 0x1f83d9ab; + ctx.state[7] = 0x5be0cd19; + ctx.bit_count = 0; + ctx.buffer_len = 0; +} + +void Sha256Update(Sha256Context &ctx, const uint8_t *data, std::size_t len) +{ + for (std::size_t i = 0; i < len; ++i) + { + ctx.buffer[ctx.buffer_len++] = data[i]; + if (ctx.buffer_len == 64) + { + Sha256ProcessBlock(ctx, ctx.buffer); + ctx.buffer_len = 0; + } + } + ctx.bit_count += static_cast(len) * 8; +} + +void Sha256Final(Sha256Context &ctx, uint8_t digest[32]) +{ + ctx.buffer[ctx.buffer_len++] = 0x80; + if (ctx.buffer_len > 56) + { + while (ctx.buffer_len < 64) + { + ctx.buffer[ctx.buffer_len++] = 0x00; + } + Sha256ProcessBlock(ctx, ctx.buffer); + ctx.buffer_len = 0; + } + while (ctx.buffer_len < 56) + { + ctx.buffer[ctx.buffer_len++] = 0x00; + } + // Append bit count as big-endian 64-bit integer. + for (int i = 7; i >= 0; --i) + { + ctx.buffer[ctx.buffer_len++] = static_cast((ctx.bit_count >> (i * 8)) & 0xFF); + } + Sha256ProcessBlock(ctx, ctx.buffer); + + for (int i = 0; i < 8; ++i) + { + digest[i * 4] = static_cast((ctx.state[i] >> 24) & 0xFF); + digest[i * 4 + 1] = static_cast((ctx.state[i] >> 16) & 0xFF); + digest[i * 4 + 2] = static_cast((ctx.state[i] >> 8) & 0xFF); + digest[i * 4 + 3] = static_cast(ctx.state[i] & 0xFF); + } +} + +// Encode the first `byte_count` bytes of `digest` as lowercase hex. +std::string DigestToHex(const uint8_t *digest, std::size_t byte_count) +{ + static const char kHex[] = "0123456789abcdef"; + std::string result; + result.reserve(byte_count * 2); + for (std::size_t i = 0; i < byte_count; ++i) + { + result += kHex[(digest[i] >> 4) & 0x0F]; + result += kHex[digest[i] & 0x0F]; + } + return result; +} + +} // namespace + +std::string GetExecutableBuildIdHtlhash(const int32_t &pid) +{ + std::string exe_path = GetExecutablePath(pid); + if (exe_path.empty()) + { + return std::string(); + } + + std::ifstream f(exe_path, std::ios::binary | std::ios::ate); + if (!f.is_open()) + { + return std::string(); + } + + auto file_size = static_cast(f.tellg()); + + constexpr std::size_t kChunkSize = 4096; + + // Read head (up to 4096 bytes). + std::string head(kChunkSize, '\0'); + f.seekg(0, std::ios::beg); + f.read(&head[0], static_cast(kChunkSize)); + std::size_t head_read = static_cast(f.gcount()); + head.resize(head_read); + + // Read tail (up to 4096 bytes from end). + std::string tail(kChunkSize, '\0'); + std::size_t tail_offset = + (file_size > kChunkSize) ? static_cast(file_size - kChunkSize) : 0; + f.seekg(static_cast(tail_offset), std::ios::beg); + f.read(&tail[0], static_cast(kChunkSize)); + std::size_t tail_read = static_cast(f.gcount()); + tail.resize(tail_read); + + // Encode file length as big-endian uint64. + std::uint64_t file_size_be = file_size; + uint8_t len_bytes[8]; + for (int i = 7; i >= 0; --i) + { + len_bytes[i] = static_cast(file_size_be & 0xFF); + file_size_be >>= 8; + } + + // SHA256(head || tail || len_bytes). + Sha256Context ctx; + Sha256Init(ctx); + Sha256Update(ctx, reinterpret_cast(head.data()), head.size()); + Sha256Update(ctx, reinterpret_cast(tail.data()), tail.size()); + Sha256Update(ctx, len_bytes, 8); + + uint8_t digest[32]; + Sha256Final(ctx, digest); + + // Return first 16 bytes (128 bits) as hex (32 hex chars). + return DigestToHex(digest, 16); +} + } // namespace detail } // namespace resource_detector OPENTELEMETRY_END_NAMESPACE From 0245e4a63ba19ad3fdbeaaa1442fc20c16b0f476 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Sat, 15 Aug 2026 16:47:29 +0530 Subject: [PATCH 03/24] Call new functions in Detect() --- resource_detectors/src/process_detector.cc | 56 +++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/resource_detectors/src/process_detector.cc b/resource_detectors/src/process_detector.cc index 8dd760bd8a..66ca4cfd65 100644 --- a/resource_detectors/src/process_detector.cc +++ b/resource_detectors/src/process_detector.cc @@ -39,7 +39,17 @@ opentelemetry::sdk::resource::Resource ProcessResourceDetector::Detect() noexcep std::string executable_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid); if (!executable_path.empty()) { - attributes[semconv::process::kProcessExecutablePath] = std::move(executable_path); + attributes[semconv::process::kProcessExecutablePath] = executable_path; + + // process.executable.name is the basename of the executable path. + std::size_t sep = executable_path.find_last_of("/\\"); + std::string executable_name = (sep == std::string::npos) + ? executable_path + : executable_path.substr(sep + 1); + if (!executable_name.empty()) + { + attributes[semconv::process::kProcessExecutableName] = std::move(executable_name); + } } } catch (const ::std::exception &ex) @@ -65,6 +75,50 @@ opentelemetry::sdk::resource::Resource ProcessResourceDetector::Detect() noexcep << "Error extracting command with arguments: " << ex.what()); } + try + { + std::string creation_time = + opentelemetry::resource_detector::detail::GetProcessCreationTime(pid); + if (!creation_time.empty()) + { + attributes[semconv::process::kProcessCreationTime] = std::move(creation_time); + } + } + catch (const std::exception &ex) + { + OTEL_INTERNAL_LOG_ERROR("[Process Resource Detector] " + << "Error extracting process creation time: " << ex.what()); + } + + try + { + std::string owner = opentelemetry::resource_detector::detail::GetProcessOwner(pid); + if (!owner.empty()) + { + attributes[semconv::process::kProcessOwner] = std::move(owner); + } + } + catch (const std::exception &ex) + { + OTEL_INTERNAL_LOG_ERROR("[Process Resource Detector] " + << "Error extracting process owner: " << ex.what()); + } + + try + { + std::string build_id = + opentelemetry::resource_detector::detail::GetExecutableBuildIdHtlhash(pid); + if (!build_id.empty()) + { + attributes[semconv::process::kProcessExecutableBuildIdHtlhash] = std::move(build_id); + } + } + catch (const std::exception &ex) + { + OTEL_INTERNAL_LOG_ERROR("[Process Resource Detector] " + << "Error computing executable build id (htlhash): " << ex.what()); + } + return ResourceDetector::Create(attributes); } From 71fea9c10483dcf3df4cf25011cf3fa6d8eeae68 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Sat, 15 Aug 2026 16:49:33 +0530 Subject: [PATCH 04/24] Update class docstrings and readme --- resource_detectors/README.md | 13 +++++++++--- .../resource_detectors/process_detector.h | 21 ++++++++++++------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/resource_detectors/README.md b/resource_detectors/README.md index 8aae5d1c49..e8842d3619 100644 --- a/resource_detectors/README.md +++ b/resource_detectors/README.md @@ -63,9 +63,16 @@ or inaccessible. | --- | --- | --- | --- | --- | | `process.pid` | Process ID | Yes | Yes | Yes | | `process.executable.path` | Path via `/proc` (Linux) or Win32 APIs | Yes | No | Yes | - -Limitation: current macOS implementation does not populate -`process.executable.path`. +| `process.executable.name` | Basename of the executable path | Yes | No | Yes | +| `process.creation.time` | Process start time in ISO 8601 UTC | Yes | Yes | Yes | +| `process.owner` | Username of the process owner | Yes | Yes | Yes | +| `process.executable.build_id.htlhash` | Deterministic SHA256-based build ID | Yes | No | Yes | + +Limitations: +- `process.executable.path`, `process.executable.name`, and + `process.executable.build_id.htlhash` are not populated on macOS because + reading `/proc//exe` is not available. A macOS implementation via + `proc_pidinfo()` would be a welcome contribution. ### Env Entity Resource Detector (Experimental) diff --git a/resource_detectors/include/opentelemetry/resource_detectors/process_detector.h b/resource_detectors/include/opentelemetry/resource_detectors/process_detector.h index 06d629796a..25ca1adb9f 100644 --- a/resource_detectors/include/opentelemetry/resource_detectors/process_detector.h +++ b/resource_detectors/include/opentelemetry/resource_detectors/process_detector.h @@ -12,20 +12,25 @@ 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. + * This detector extracts metadata such as process ID, executable path, executable name, + * process creation time, process owner, and executable build ID, then sets attributes + * following the OpenTelemetry semantic conventions: + * + * - process.pid (required) — current process identifier + * - process.executable.path (recommended) — full path via /proc or Win32 APIs + * - process.executable.name (recommended) — basename of the executable path + * - process.creation.time (required) — ISO 8601 UTC creation timestamp + * - process.owner (recommended) — username of the process owner + * - process.executable.build_id.htlhash (required) — deterministic SHA256-based build ID + * + * Attributes that cannot be determined on the current platform are omitted. */ 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. + * See the class-level documentation for the complete list of attributes populated. */ opentelemetry::sdk::resource::Resource Detect() noexcept override; }; From dd0842acb13b9d982fc69e42255a6c3bb392b213 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Sat, 15 Aug 2026 16:49:54 +0530 Subject: [PATCH 05/24] Add unit tests and integration tests --- .../test/process_detector_test.cc | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/resource_detectors/test/process_detector_test.cc b/resource_detectors/test/process_detector_test.cc index 4782c18d22..a8e845f857 100644 --- a/resource_detectors/test/process_detector_test.cc +++ b/resource_detectors/test/process_detector_test.cc @@ -21,6 +21,9 @@ #endif #include "opentelemetry/resource_detectors/detail/process_detector_utils.h" +#include "opentelemetry/resource_detectors/process_detector.h" +#include "opentelemetry/sdk/resource/resource.h" +#include "opentelemetry/semconv/incubating/process_attributes.h" TEST(ProcessDetectorUtilsTest, FormFilePath) { @@ -188,3 +191,125 @@ TEST(ProcessDetectorUtilsTest, GetCommandWithArgsTest) opentelemetry::resource_detector::detail::GetCommandWithArgs(pid); EXPECT_EQ(args, expected_args); } + +// --------------------------------------------------------------------------- +// New utility tests +// --------------------------------------------------------------------------- + +TEST(ProcessDetectorUtilsTest, GetExecutableNameTest) +{ + int32_t pid = getpid(); + std::string exe_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid); + std::string exe_name = opentelemetry::resource_detector::detail::GetExecutableName(pid); + + if (exe_path.empty()) + { + EXPECT_TRUE(exe_name.empty()) << "Name should be empty when path is empty"; + return; + } + + EXPECT_FALSE(exe_name.empty()) << "Executable name must not be empty when path is available"; + // The name must be a suffix of the path. + EXPECT_NE(exe_path.find(exe_name), std::string::npos) + << "Executable name '" << exe_name << "' should be a substring of path '" << exe_path << "'"; + // The name must not contain directory separators. + EXPECT_EQ(exe_name.find('/'), std::string::npos) << "Name should not contain '/'"; + EXPECT_EQ(exe_name.find('\\'), std::string::npos) << "Name should not contain '\\'"; +} + +TEST(ProcessDetectorUtilsTest, GetProcessCreationTimeTest) +{ + int32_t pid = getpid(); + std::string iso_time = opentelemetry::resource_detector::detail::GetProcessCreationTime(pid); + +#if defined(_MSC_VER) || defined(__linux__) || defined(__APPLE__) + // On supported platforms we expect a non-empty ISO 8601 result. + EXPECT_FALSE(iso_time.empty()) << "Creation time should be non-empty on this platform"; + + if (!iso_time.empty()) + { + // Very basic format check: "YYYY-MM-DDTHH:MM:SS.mmmZ" = 24 chars. + EXPECT_GE(iso_time.size(), 20u) << "ISO 8601 string too short: " << iso_time; + EXPECT_EQ(iso_time[4], '-') << "Expected '-' at index 4: " << iso_time; + EXPECT_EQ(iso_time[7], '-') << "Expected '-' at index 7: " << iso_time; + EXPECT_EQ(iso_time[10], 'T') << "Expected 'T' at index 10: " << iso_time; + EXPECT_EQ(iso_time.back(), 'Z') << "Expected 'Z' at end: " << iso_time; + } +#else + // On unsupported platforms accept an empty string gracefully. + (void)iso_time; +#endif +} + +TEST(ProcessDetectorUtilsTest, GetProcessOwnerTest) +{ + int32_t pid = getpid(); + std::string owner = opentelemetry::resource_detector::detail::GetProcessOwner(pid); + + // On all supported platforms the effective user name must be non-empty. + EXPECT_FALSE(owner.empty()) << "Process owner should be non-empty"; + // Sanity: no newline characters in the username. + EXPECT_EQ(owner.find('\n'), std::string::npos) << "Owner should not contain newline"; +} + +TEST(ProcessDetectorUtilsTest, GetExecutableBuildIdHtlhashTest) +{ + int32_t pid = getpid(); + std::string hash1 = opentelemetry::resource_detector::detail::GetExecutableBuildIdHtlhash(pid); + std::string hash2 = opentelemetry::resource_detector::detail::GetExecutableBuildIdHtlhash(pid); + + EXPECT_FALSE(hash1.empty()) << "Build ID htlhash must not be empty"; + + if (!hash1.empty()) + { + // Must be exactly 32 lowercase hex characters (16 bytes). + EXPECT_EQ(hash1.size(), 32u) << "htlhash must be 32 hex chars, got: " << hash1; + for (char c : hash1) + { + EXPECT_TRUE((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) + << "Non-hex character '" << c << "' in htlhash: " << hash1; + } + // Must be deterministic: two calls on the same process → same result. + EXPECT_EQ(hash1, hash2) << "htlhash must be deterministic"; + } +} + +// --------------------------------------------------------------------------- +// Integration test — Detect() attribute presence +// --------------------------------------------------------------------------- + +TEST(ProcessResourceDetectorTest, DetectPopulatesExpectedAttributes) +{ + opentelemetry::resource_detector::ProcessResourceDetector detector; + opentelemetry::sdk::resource::Resource resource = detector.Detect(); + const auto &attrs = resource.GetAttributes(); + + // process.pid — always present. + EXPECT_NE(attrs.find(opentelemetry::semconv::process::kProcessPid), attrs.end()) + << "process.pid must be present"; + +#if defined(_MSC_VER) || defined(__linux__) + // process.executable.path — present on Linux and Windows. + EXPECT_NE(attrs.find(opentelemetry::semconv::process::kProcessExecutablePath), attrs.end()) + << "process.executable.path must be present on this platform"; + + // process.executable.name — present whenever executable.path is. + EXPECT_NE(attrs.find(opentelemetry::semconv::process::kProcessExecutableName), attrs.end()) + << "process.executable.name must be present on this platform"; + + // process.executable.build_id.htlhash — present on Linux and Windows. + EXPECT_NE( + attrs.find(opentelemetry::semconv::process::kProcessExecutableBuildIdHtlhash), attrs.end()) + << "process.executable.build_id.htlhash must be present on this platform"; +#endif + +#if defined(_MSC_VER) || defined(__linux__) || defined(__APPLE__) + // process.creation.time — present on Linux, macOS, and Windows. + EXPECT_NE(attrs.find(opentelemetry::semconv::process::kProcessCreationTime), attrs.end()) + << "process.creation.time must be present on this platform"; + + // process.owner — present on Linux, macOS, and Windows. + EXPECT_NE(attrs.find(opentelemetry::semconv::process::kProcessOwner), attrs.end()) + << "process.owner must be present on this platform"; +#endif +} From 92a1b974f359802356fac5d990deb8cda115b10c Mon Sep 17 00:00:00 2001 From: Pradeep Date: Sat, 15 Aug 2026 17:21:28 +0530 Subject: [PATCH 06/24] Fix test on macOS for GetExecutableBuildIdHtlhashTest --- resource_detectors/test/process_detector_test.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/resource_detectors/test/process_detector_test.cc b/resource_detectors/test/process_detector_test.cc index a8e845f857..729a96ae26 100644 --- a/resource_detectors/test/process_detector_test.cc +++ b/resource_detectors/test/process_detector_test.cc @@ -255,9 +255,16 @@ TEST(ProcessDetectorUtilsTest, GetProcessOwnerTest) TEST(ProcessDetectorUtilsTest, GetExecutableBuildIdHtlhashTest) { int32_t pid = getpid(); + std::string exe_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid); std::string hash1 = opentelemetry::resource_detector::detail::GetExecutableBuildIdHtlhash(pid); std::string hash2 = opentelemetry::resource_detector::detail::GetExecutableBuildIdHtlhash(pid); + if (exe_path.empty()) + { + EXPECT_TRUE(hash1.empty()) << "htlhash should be empty when executable path is empty"; + return; + } + EXPECT_FALSE(hash1.empty()) << "Build ID htlhash must not be empty"; if (!hash1.empty()) From f5f1ac73800ee360e3db1feaeb90220d2afe4c58 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Tue, 18 Aug 2026 04:52:34 +0530 Subject: [PATCH 07/24] Fix clang-format violations --- resource_detectors/src/process_detector.cc | 9 ++-- .../src/process_detector_utils.cc | 53 +++++++++---------- .../test/process_detector_test.cc | 18 +++---- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/resource_detectors/src/process_detector.cc b/resource_detectors/src/process_detector.cc index 66ca4cfd65..a3f6d1bfc2 100644 --- a/resource_detectors/src/process_detector.cc +++ b/resource_detectors/src/process_detector.cc @@ -43,9 +43,8 @@ opentelemetry::sdk::resource::Resource ProcessResourceDetector::Detect() noexcep // process.executable.name is the basename of the executable path. std::size_t sep = executable_path.find_last_of("/\\"); - std::string executable_name = (sep == std::string::npos) - ? executable_path - : executable_path.substr(sep + 1); + std::string executable_name = + (sep == std::string::npos) ? executable_path : executable_path.substr(sep + 1); if (!executable_name.empty()) { attributes[semconv::process::kProcessExecutableName] = std::move(executable_name); @@ -100,8 +99,8 @@ opentelemetry::sdk::resource::Resource ProcessResourceDetector::Detect() noexcep } catch (const std::exception &ex) { - OTEL_INTERNAL_LOG_ERROR("[Process Resource Detector] " - << "Error extracting process owner: " << ex.what()); + OTEL_INTERNAL_LOG_ERROR("[Process Resource Detector] " << "Error extracting process owner: " + << ex.what()); } try diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index b2e61f224b..9bf5dc1b5c 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -165,9 +165,8 @@ std::string FileTimeToIso8601(const FILETIME &ft) return std::string(); } char buf[32]; - std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", - static_cast(st.wYear), static_cast(st.wMonth), - static_cast(st.wDay), static_cast(st.wHour), + std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", static_cast(st.wYear), + static_cast(st.wMonth), static_cast(st.wDay), static_cast(st.wHour), static_cast(st.wMinute), static_cast(st.wSecond), static_cast(st.wMilliseconds)); return std::string(buf); @@ -270,9 +269,9 @@ std::string GetProcessCreationTime(const int32_t &pid) struct tm utc_time = {}; gmtime_r(&secs, &utc_time); char buf[32]; - std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03ldZ", - utc_time.tm_year + 1900, utc_time.tm_mon + 1, utc_time.tm_mday, - utc_time.tm_hour, utc_time.tm_min, utc_time.tm_sec, usecs / 1000); + std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03ldZ", utc_time.tm_year + 1900, + utc_time.tm_mon + 1, utc_time.tm_mday, utc_time.tm_hour, utc_time.tm_min, + utc_time.tm_sec, usecs / 1000); return std::string(buf); #else @@ -296,7 +295,7 @@ std::string GetProcessCreationTime(const int32_t &pid) return std::string(); } - const auto clk = static_cast(clk_tck); + const auto clk = static_cast(clk_tck); unsigned long long start_secs = boot_time_secs + starttime_ticks / clk; unsigned long long start_msecs = (starttime_ticks % clk) * 1000 / clk; @@ -305,9 +304,9 @@ std::string GetProcessCreationTime(const int32_t &pid) gmtime_r(&t, &utc_time); char buf[32]; - std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03lluZ", - utc_time.tm_year + 1900, utc_time.tm_mon + 1, utc_time.tm_mday, - utc_time.tm_hour, utc_time.tm_min, utc_time.tm_sec, start_msecs); + std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03lluZ", utc_time.tm_year + 1900, + utc_time.tm_mon + 1, utc_time.tm_mday, utc_time.tm_hour, utc_time.tm_min, + utc_time.tm_sec, start_msecs); return std::string(buf); #endif } @@ -401,16 +400,14 @@ struct Sha256Context }; static const uint32_t kSha256K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, - 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, - 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, - 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, - 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, - 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, - 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, - 0xc67178f2}; + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; inline uint32_t Rotr32(uint32_t x, int n) { @@ -468,14 +465,14 @@ void Sha256ProcessBlock(Sha256Context &ctx, const uint8_t block[64]) void Sha256Init(Sha256Context &ctx) { - ctx.state[0] = 0x6a09e667; - ctx.state[1] = 0xbb67ae85; - ctx.state[2] = 0x3c6ef372; - ctx.state[3] = 0xa54ff53a; - ctx.state[4] = 0x510e527f; - ctx.state[5] = 0x9b05688c; - ctx.state[6] = 0x1f83d9ab; - ctx.state[7] = 0x5be0cd19; + ctx.state[0] = 0x6a09e667; + ctx.state[1] = 0xbb67ae85; + ctx.state[2] = 0x3c6ef372; + ctx.state[3] = 0xa54ff53a; + ctx.state[4] = 0x510e527f; + ctx.state[5] = 0x9b05688c; + ctx.state[6] = 0x1f83d9ab; + ctx.state[7] = 0x5be0cd19; ctx.bit_count = 0; ctx.buffer_len = 0; } diff --git a/resource_detectors/test/process_detector_test.cc b/resource_detectors/test/process_detector_test.cc index 729a96ae26..565f32a2ad 100644 --- a/resource_detectors/test/process_detector_test.cc +++ b/resource_detectors/test/process_detector_test.cc @@ -198,9 +198,9 @@ TEST(ProcessDetectorUtilsTest, GetCommandWithArgsTest) TEST(ProcessDetectorUtilsTest, GetExecutableNameTest) { - int32_t pid = getpid(); - std::string exe_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid); - std::string exe_name = opentelemetry::resource_detector::detail::GetExecutableName(pid); + int32_t pid = getpid(); + std::string exe_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid); + std::string exe_name = opentelemetry::resource_detector::detail::GetExecutableName(pid); if (exe_path.empty()) { @@ -243,7 +243,7 @@ TEST(ProcessDetectorUtilsTest, GetProcessCreationTimeTest) TEST(ProcessDetectorUtilsTest, GetProcessOwnerTest) { - int32_t pid = getpid(); + int32_t pid = getpid(); std::string owner = opentelemetry::resource_detector::detail::GetProcessOwner(pid); // On all supported platforms the effective user name must be non-empty. @@ -254,10 +254,10 @@ TEST(ProcessDetectorUtilsTest, GetProcessOwnerTest) TEST(ProcessDetectorUtilsTest, GetExecutableBuildIdHtlhashTest) { - int32_t pid = getpid(); + int32_t pid = getpid(); std::string exe_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid); - std::string hash1 = opentelemetry::resource_detector::detail::GetExecutableBuildIdHtlhash(pid); - std::string hash2 = opentelemetry::resource_detector::detail::GetExecutableBuildIdHtlhash(pid); + std::string hash1 = opentelemetry::resource_detector::detail::GetExecutableBuildIdHtlhash(pid); + std::string hash2 = opentelemetry::resource_detector::detail::GetExecutableBuildIdHtlhash(pid); if (exe_path.empty()) { @@ -305,8 +305,8 @@ TEST(ProcessResourceDetectorTest, DetectPopulatesExpectedAttributes) << "process.executable.name must be present on this platform"; // process.executable.build_id.htlhash — present on Linux and Windows. - EXPECT_NE( - attrs.find(opentelemetry::semconv::process::kProcessExecutableBuildIdHtlhash), attrs.end()) + EXPECT_NE(attrs.find(opentelemetry::semconv::process::kProcessExecutableBuildIdHtlhash), + attrs.end()) << "process.executable.build_id.htlhash must be present on this platform"; #endif From f696bf48a2e25dce2c985aae25301a4ab23c1617 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Tue, 18 Aug 2026 07:20:11 +0530 Subject: [PATCH 08/24] Combine GetExecutableName and GetExecutablePath into GetExecutableInfo with other minor changes --- .../detail/process_detector_utils.h | 30 +++--- resource_detectors/src/process_detector.cc | 16 ++-- .../src/process_detector_utils.cc | 93 +++++++++++-------- .../test/process_detector_test.cc | 28 +++++- 4 files changed, 100 insertions(+), 67 deletions(-) diff --git a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h index 79b02c1a75..699ce838cf 100644 --- a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h +++ b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h @@ -15,6 +15,15 @@ namespace resource_detector namespace detail { +/** + * Contains the path and name of the executable. + */ +struct ExecutableInfo +{ + std::string path; + std::string name; +}; + /** * Forms a file path for a process type based on the given PID. * for example - /proc//cmdline, /proc//exe @@ -22,7 +31,7 @@ namespace detail std::string FormFilePath(const int32_t &pid, const char *process_type); /** - * Retrieves the absolute file system path to the executable for a given PID. + * Retrieves the absolute file system path and the base name of the process executable. * Platform-specific behavior: * - Windows: Uses OpenProcess() + GetProcessImageFileNameW(). * - Linux/Unix: Reads the /proc//exe symbolic link. @@ -30,16 +39,7 @@ std::string FormFilePath(const int32_t &pid, const char *process_type); * * @param pid Process ID. */ -std::string GetExecutablePath(const int32_t &pid); - -/** - * Returns the base name (filename) of the process executable. - * Derived from GetExecutablePath() by stripping the directory components. - * Platform-specific behavior mirrors GetExecutablePath(). - * - * @param pid Process ID. - */ -std::string GetExecutableName(const int32_t &pid); +ExecutableInfo GetExecutableInfo(const int32_t &pid); /** * Extracts the command-line arguments and the command. @@ -78,7 +78,7 @@ std::string GetProcessCreationTime(const int32_t &pid); * * @param pid Process ID. */ -std::string GetProcessOwner(const int32_t &pid); +std::string GetProcessOwner(); /** * Computes the deterministic htlhash build ID for the process executable. @@ -90,6 +90,12 @@ std::string GetProcessOwner(const int32_t &pid); */ std::string GetExecutableBuildIdHtlhash(const int32_t &pid); +/** + * Computes a SHA-256 hash of the given data and returns it as a lowercase hex string. + * This is exposed primarily for unit testing the internal SHA-256 implementation. + */ +std::string ComputeSha256Hex(const std::string &data); + } // namespace detail } // namespace resource_detector OPENTELEMETRY_END_NAMESPACE diff --git a/resource_detectors/src/process_detector.cc b/resource_detectors/src/process_detector.cc index a3f6d1bfc2..673ece152b 100644 --- a/resource_detectors/src/process_detector.cc +++ b/resource_detectors/src/process_detector.cc @@ -36,18 +36,14 @@ opentelemetry::sdk::resource::Resource ProcessResourceDetector::Detect() noexcep try { - std::string executable_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid); - if (!executable_path.empty()) + auto exe_info = opentelemetry::resource_detector::detail::GetExecutableInfo(pid); + if (!exe_info.path.empty()) { - attributes[semconv::process::kProcessExecutablePath] = executable_path; + attributes[semconv::process::kProcessExecutablePath] = std::move(exe_info.path); - // process.executable.name is the basename of the executable path. - std::size_t sep = executable_path.find_last_of("/\\"); - std::string executable_name = - (sep == std::string::npos) ? executable_path : executable_path.substr(sep + 1); - if (!executable_name.empty()) + if (!exe_info.name.empty()) { - attributes[semconv::process::kProcessExecutableName] = std::move(executable_name); + attributes[semconv::process::kProcessExecutableName] = std::move(exe_info.name); } } } @@ -91,7 +87,7 @@ opentelemetry::sdk::resource::Resource ProcessResourceDetector::Detect() noexcep try { - std::string owner = opentelemetry::resource_detector::detail::GetProcessOwner(pid); + std::string owner = opentelemetry::resource_detector::detail::GetProcessOwner(); if (!owner.empty()) { attributes[semconv::process::kProcessOwner] = std::move(owner); diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 9bf5dc1b5c..555fe446ee 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -20,6 +20,14 @@ # include #endif +#ifdef __APPLE__ +# include +#endif + +#ifndef _MSC_VER +# include +#endif + #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -31,14 +39,15 @@ namespace detail constexpr const char *kExecutableName = "exe"; constexpr const char *kCmdlineName = "cmdline"; -std::string GetExecutablePath(const int32_t &pid) +ExecutableInfo GetExecutableInfo(const int32_t &pid) { + ExecutableInfo info; #ifdef _MSC_VER HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, static_cast(pid)); if (!hProcess) { - return std::string(); + return info; } WCHAR wbuffer[MAX_PATH]; @@ -47,7 +56,7 @@ std::string GetExecutablePath(const int32_t &pid) if (len == 0) { - return std::string(); + return info; } // Convert UTF-16 to UTF-8 @@ -55,36 +64,32 @@ std::string GetExecutablePath(const int32_t &pid) std::string utf8_path(size_needed, 0); WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, &utf8_path[0], size_needed, NULL, NULL); - return utf8_path; + info.path = utf8_path; #else - std::string path = FormFilePath(pid, kExecutableName); + std::string proc_path = FormFilePath(pid, kExecutableName); char buffer[4096]; - ssize_t len = readlink(path.c_str(), buffer, sizeof(buffer) - 1); + ssize_t len = readlink(proc_path.c_str(), buffer, sizeof(buffer) - 1); if (len != -1) { buffer[len] = '\0'; - return std::string(buffer); + info.path = std::string(buffer); } - - return std::string(); #endif -} -std::string GetExecutableName(const int32_t &pid) -{ - std::string path = GetExecutablePath(pid); - if (path.empty()) - { - return std::string(); - } - // Find last path separator (works for both '/' and '\'). - std::size_t sep = path.find_last_of("/\\"); - if (sep == std::string::npos) + if (!info.path.empty()) { - return path; + std::size_t sep = info.path.find_last_of("/\\"); + if (sep != std::string::npos) + { + info.name = info.path.substr(sep + 1); + } + else + { + info.name = info.path; + } } - return path.substr(sep + 1); + return info; } std::vector ExtractCommandWithArgs(const std::string &command_line_path) @@ -234,10 +239,6 @@ bool ReadBootTimeSecs(unsigned long long &boot_time) } // namespace #endif // !_MSC_VER && !__APPLE__ -#ifdef __APPLE__ -# include -#endif - std::string GetProcessCreationTime(const int32_t &pid) { #ifdef _MSC_VER @@ -315,11 +316,7 @@ std::string GetProcessCreationTime(const int32_t &pid) // GetProcessOwner // --------------------------------------------------------------------------- -#ifndef _MSC_VER -# include -#endif - -std::string GetProcessOwner(const int32_t & /* pid */) +std::string GetProcessOwner() { #ifdef _MSC_VER // On Windows, open the current process token and look up the account SID. @@ -541,7 +538,7 @@ std::string DigestToHex(const uint8_t *digest, std::size_t byte_count) std::string GetExecutableBuildIdHtlhash(const int32_t &pid) { - std::string exe_path = GetExecutablePath(pid); + std::string exe_path = GetExecutableInfo(pid).path; if (exe_path.empty()) { return std::string(); @@ -564,14 +561,17 @@ std::string GetExecutableBuildIdHtlhash(const int32_t &pid) std::size_t head_read = static_cast(f.gcount()); head.resize(head_read); - // Read tail (up to 4096 bytes from end). - std::string tail(kChunkSize, '\0'); - std::size_t tail_offset = - (file_size > kChunkSize) ? static_cast(file_size - kChunkSize) : 0; - f.seekg(static_cast(tail_offset), std::ios::beg); - f.read(&tail[0], static_cast(kChunkSize)); - std::size_t tail_read = static_cast(f.gcount()); - tail.resize(tail_read); + // Read tail (up to 4096 bytes from end) only if file is larger than 4096 bytes. + std::string tail; + if (file_size > kChunkSize) + { + tail.resize(kChunkSize, '\0'); + std::size_t tail_offset = static_cast(file_size - kChunkSize); + f.seekg(static_cast(tail_offset), std::ios::beg); + f.read(&tail[0], static_cast(kChunkSize)); + std::size_t tail_read = static_cast(f.gcount()); + tail.resize(tail_read); + } // Encode file length as big-endian uint64. std::uint64_t file_size_be = file_size; @@ -596,6 +596,19 @@ std::string GetExecutableBuildIdHtlhash(const int32_t &pid) return DigestToHex(digest, 16); } +std::string ComputeSha256Hex(const std::string &data) +{ + Sha256Context ctx; + Sha256Init(ctx); + Sha256Update(ctx, reinterpret_cast(data.data()), data.size()); + + uint8_t digest[32]; + Sha256Final(ctx, digest); + + // Return all 32 bytes (256 bits) as hex (64 hex chars). + return DigestToHex(digest, 32); +} + } // namespace detail } // namespace resource_detector OPENTELEMETRY_END_NAMESPACE diff --git a/resource_detectors/test/process_detector_test.cc b/resource_detectors/test/process_detector_test.cc index 565f32a2ad..bab7f145d0 100644 --- a/resource_detectors/test/process_detector_test.cc +++ b/resource_detectors/test/process_detector_test.cc @@ -111,7 +111,7 @@ TEST(ProcessDetectorUtilsTest, GetExecutablePathTest) path = std::string(); } #endif - std::string expected_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid); + std::string expected_path = opentelemetry::resource_detector::detail::GetExecutableInfo(pid).path; EXPECT_EQ(path, expected_path); } @@ -199,8 +199,9 @@ TEST(ProcessDetectorUtilsTest, GetCommandWithArgsTest) TEST(ProcessDetectorUtilsTest, GetExecutableNameTest) { int32_t pid = getpid(); - std::string exe_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid); - std::string exe_name = opentelemetry::resource_detector::detail::GetExecutableName(pid); + auto exe_info = opentelemetry::resource_detector::detail::GetExecutableInfo(pid); + std::string exe_path = exe_info.path; + std::string exe_name = exe_info.name; if (exe_path.empty()) { @@ -244,7 +245,7 @@ TEST(ProcessDetectorUtilsTest, GetProcessCreationTimeTest) TEST(ProcessDetectorUtilsTest, GetProcessOwnerTest) { int32_t pid = getpid(); - std::string owner = opentelemetry::resource_detector::detail::GetProcessOwner(pid); + std::string owner = opentelemetry::resource_detector::detail::GetProcessOwner(); // On all supported platforms the effective user name must be non-empty. EXPECT_FALSE(owner.empty()) << "Process owner should be non-empty"; @@ -255,7 +256,7 @@ TEST(ProcessDetectorUtilsTest, GetProcessOwnerTest) TEST(ProcessDetectorUtilsTest, GetExecutableBuildIdHtlhashTest) { int32_t pid = getpid(); - std::string exe_path = opentelemetry::resource_detector::detail::GetExecutablePath(pid); + std::string exe_path = opentelemetry::resource_detector::detail::GetExecutableInfo(pid).path; std::string hash1 = opentelemetry::resource_detector::detail::GetExecutableBuildIdHtlhash(pid); std::string hash2 = opentelemetry::resource_detector::detail::GetExecutableBuildIdHtlhash(pid); @@ -285,6 +286,23 @@ TEST(ProcessDetectorUtilsTest, GetExecutableBuildIdHtlhashTest) // Integration test — Detect() attribute presence // --------------------------------------------------------------------------- +TEST(ProcessDetectorUtilsTest, ComputeSha256HexTest) +{ + // Test vectors from NIST FIPS 180-4 + // 1. Empty string + EXPECT_EQ(opentelemetry::resource_detector::detail::ComputeSha256Hex(""), + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + + // 2. "abc" + EXPECT_EQ(opentelemetry::resource_detector::detail::ComputeSha256Hex("abc"), + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + + // 3. "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + EXPECT_EQ(opentelemetry::resource_detector::detail::ComputeSha256Hex( + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"), + "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); +} + TEST(ProcessResourceDetectorTest, DetectPopulatesExpectedAttributes) { opentelemetry::resource_detector::ProcessResourceDetector detector; From cdde1dafa9715474be77de24187284b0aa6e4609 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 19 Aug 2026 00:59:31 +0530 Subject: [PATCH 09/24] Type and entity fixes --- .../resource_detectors/process_detector.h | 7 +++-- .../src/process_detector_utils.cc | 26 +++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/resource_detectors/include/opentelemetry/resource_detectors/process_detector.h b/resource_detectors/include/opentelemetry/resource_detectors/process_detector.h index 25ca1adb9f..3c0c360be3 100644 --- a/resource_detectors/include/opentelemetry/resource_detectors/process_detector.h +++ b/resource_detectors/include/opentelemetry/resource_detectors/process_detector.h @@ -16,11 +16,14 @@ namespace resource_detector * process creation time, process owner, and executable build ID, then sets attributes * following the OpenTelemetry semantic conventions: * + * Process entity attributes: * - process.pid (required) — current process identifier - * - process.executable.path (recommended) — full path via /proc or Win32 APIs - * - process.executable.name (recommended) — basename of the executable path * - process.creation.time (required) — ISO 8601 UTC creation timestamp * - process.owner (recommended) — username of the process owner + * + * Process Executable entity attributes: + * - process.executable.path (recommended) — full path via /proc or Win32 APIs + * - process.executable.name (recommended) — basename of the executable path * - process.executable.build_id.htlhash (required) — deterministic SHA256-based build ID * * Attributes that cannot be determined on the current platform are omitted. diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 555fe446ee..8c07b0d4c8 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -184,7 +184,7 @@ namespace { // Parse the 22nd field (starttime, in clock ticks since boot) from /proc//stat. // The comm field (2nd) may contain spaces/parens, so we scan past the closing ')'. -bool ParseStarttimeFromProcStat(const std::string &stat_path, unsigned long long &starttime_ticks) +bool ParseStarttimeFromProcStat(const std::string &stat_path, uint64_t &starttime_ticks) { std::ifstream f(stat_path); if (!f.is_open()) @@ -218,7 +218,7 @@ bool ParseStarttimeFromProcStat(const std::string &stat_path, unsigned long long } // Read boot time in seconds since epoch from /proc/stat. -bool ReadBootTimeSecs(unsigned long long &boot_time) +bool ReadBootTimeSecs(uint64_t &boot_time) { std::ifstream f("/proc/stat"); if (!f.is_open()) @@ -266,7 +266,7 @@ std::string GetProcessCreationTime(const int32_t &pid) } // kp_proc.p_starttime is a struct timeval (seconds + microseconds). time_t secs = kp.kp_proc.p_starttime.tv_sec; - long usecs = kp.kp_proc.p_starttime.tv_usec; + int64_t usecs = kp.kp_proc.p_starttime.tv_usec; struct tm utc_time = {}; gmtime_r(&secs, &utc_time); char buf[32]; @@ -277,8 +277,8 @@ std::string GetProcessCreationTime(const int32_t &pid) #else // Linux: starttime (ticks since boot) from /proc//stat + btime from /proc/stat. - unsigned long long starttime_ticks = 0; - unsigned long long boot_time_secs = 0; + uint64_t starttime_ticks = 0; + uint64_t boot_time_secs = 0; std::string stat_path = FormFilePath(pid, "stat"); if (!ParseStarttimeFromProcStat(stat_path, starttime_ticks)) @@ -290,15 +290,15 @@ std::string GetProcessCreationTime(const int32_t &pid) return std::string(); } - long clk_tck = sysconf(_SC_CLK_TCK); + int64_t clk_tck = sysconf(_SC_CLK_TCK); if (clk_tck <= 0) { return std::string(); } - const auto clk = static_cast(clk_tck); - unsigned long long start_secs = boot_time_secs + starttime_ticks / clk; - unsigned long long start_msecs = (starttime_ticks % clk) * 1000 / clk; + const auto clk = static_cast(clk_tck); + uint64_t start_secs = boot_time_secs + starttime_ticks / clk; + uint64_t start_msecs = (starttime_ticks % clk) * 1000 / clk; time_t t = static_cast(start_secs); struct tm utc_time = {}; @@ -390,10 +390,10 @@ namespace // Reference: FIPS 180-4 struct Sha256Context { - uint32_t state[8]; - uint64_t bit_count; - uint8_t buffer[64]; - uint32_t buffer_len; + uint32_t state[8] = {0}; + uint64_t bit_count = 0; + uint8_t buffer[64] = {0}; + uint32_t buffer_len = 0; }; static const uint32_t kSha256K[64] = { From fd5404ef07dd4b03d5a339cd4bd0e9547310106d Mon Sep 17 00:00:00 2001 From: Pradeep Date: Wed, 19 Aug 2026 11:25:19 +0530 Subject: [PATCH 10/24] MS CI failure fix --- resource_detectors/src/process_detector_utils.cc | 5 +++-- resource_detectors/test/process_detector_test.cc | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 8c07b0d4c8..c88e15b801 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -51,10 +51,11 @@ ExecutableInfo GetExecutableInfo(const int32_t &pid) } WCHAR wbuffer[MAX_PATH]; - DWORD len = GetProcessImageFileNameW(hProcess, wbuffer, MAX_PATH); + DWORD len = MAX_PATH; + BOOL success = QueryFullProcessImageNameW(hProcess, 0, wbuffer, &len); CloseHandle(hProcess); - if (len == 0) + if (!success || len == 0) { return info; } diff --git a/resource_detectors/test/process_detector_test.cc b/resource_detectors/test/process_detector_test.cc index bab7f145d0..1f1ded4fef 100644 --- a/resource_detectors/test/process_detector_test.cc +++ b/resource_detectors/test/process_detector_test.cc @@ -244,7 +244,6 @@ TEST(ProcessDetectorUtilsTest, GetProcessCreationTimeTest) TEST(ProcessDetectorUtilsTest, GetProcessOwnerTest) { - int32_t pid = getpid(); std::string owner = opentelemetry::resource_detector::detail::GetProcessOwner(); // On all supported platforms the effective user name must be non-empty. From ef03ba2a8c98f143ceef23f394a92240b5a1ef7d Mon Sep 17 00:00:00 2001 From: Pradeep Date: Fri, 21 Aug 2026 19:44:09 +0530 Subject: [PATCH 11/24] Add imports for Windows, sync docs,fix tellg() validation --- .../detail/process_detector_utils.h | 2 +- .../src/process_detector_utils.cc | 14 +++++++++++-- .../test/process_detector_test.cc | 20 ++++++++++++------- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h index 699ce838cf..61090c352a 100644 --- a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h +++ b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h @@ -33,7 +33,7 @@ std::string FormFilePath(const int32_t &pid, const char *process_type); /** * Retrieves the absolute file system path and the base name of the process executable. * Platform-specific behavior: - * - Windows: Uses OpenProcess() + GetProcessImageFileNameW(). + * - Windows: Uses OpenProcess() + QueryFullProcessImageNameW(). * - Linux/Unix: Reads the /proc//exe symbolic link. * - TODO: Need to implement for Darwin * diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index c88e15b801..a6fc576d4b 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -3,6 +3,8 @@ #include "opentelemetry/resource_detectors/detail/process_detector_utils.h" +#include +#include #include #include #include @@ -17,7 +19,6 @@ #else # include # include -# include #endif #ifdef __APPLE__ @@ -62,6 +63,10 @@ ExecutableInfo GetExecutableInfo(const int32_t &pid) // Convert UTF-16 to UTF-8 int size_needed = WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, NULL, 0, NULL, NULL); + if (size_needed <= 0) + { + return info; + } std::string utf8_path(size_needed, 0); WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, &utf8_path[0], size_needed, NULL, NULL); @@ -551,7 +556,12 @@ std::string GetExecutableBuildIdHtlhash(const int32_t &pid) return std::string(); } - auto file_size = static_cast(f.tellg()); + const auto end_pos = f.tellg(); + if (end_pos < 0) + { + return std::string(); + } + auto file_size = static_cast(end_pos); constexpr std::size_t kChunkSize = 4096; diff --git a/resource_detectors/test/process_detector_test.cc b/resource_detectors/test/process_detector_test.cc index 1f1ded4fef..6c0b4228f9 100644 --- a/resource_detectors/test/process_detector_test.cc +++ b/resource_detectors/test/process_detector_test.cc @@ -78,22 +78,28 @@ TEST(ProcessDetectorUtilsTest, GetExecutablePathTest) } else { - WCHAR wbuffer[MAX_PATH]; - DWORD len = GetProcessImageFileNameW(hProcess, wbuffer, MAX_PATH); + DWORD len = MAX_PATH; + BOOL success = QueryFullProcessImageNameW(hProcess, 0, wbuffer, &len); CloseHandle(hProcess); - if (len == 0) + if (!success || len == 0) { path = std::string(); } else { 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); - - path = utf8_path; + if (size_needed > 0) + { + std::string utf8_path(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, &utf8_path[0], size_needed, NULL, NULL); + path = utf8_path; + } + else + { + path = std::string(); + } } } #else From c6be17d1708c2d6d130f84cabf2a7b04c4b99612 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Fri, 21 Aug 2026 19:48:47 +0530 Subject: [PATCH 12/24] fix formatting --- resource_detectors/src/process_detector_utils.cc | 2 +- resource_detectors/test/process_detector_test.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index a6fc576d4b..e41c7140c8 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -52,7 +52,7 @@ ExecutableInfo GetExecutableInfo(const int32_t &pid) } WCHAR wbuffer[MAX_PATH]; - DWORD len = MAX_PATH; + DWORD len = MAX_PATH; BOOL success = QueryFullProcessImageNameW(hProcess, 0, wbuffer, &len); CloseHandle(hProcess); diff --git a/resource_detectors/test/process_detector_test.cc b/resource_detectors/test/process_detector_test.cc index 6c0b4228f9..c665aa6a1b 100644 --- a/resource_detectors/test/process_detector_test.cc +++ b/resource_detectors/test/process_detector_test.cc @@ -79,7 +79,7 @@ TEST(ProcessDetectorUtilsTest, GetExecutablePathTest) else { WCHAR wbuffer[MAX_PATH]; - DWORD len = MAX_PATH; + DWORD len = MAX_PATH; BOOL success = QueryFullProcessImageNameW(hProcess, 0, wbuffer, &len); CloseHandle(hProcess); From ad4ae2d5016ce38e17c6662048bd2c4349960cdc Mon Sep 17 00:00:00 2001 From: Pradeep Date: Fri, 21 Aug 2026 20:17:56 +0530 Subject: [PATCH 13/24] fix Readme lint issue --- resource_detectors/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/resource_detectors/README.md b/resource_detectors/README.md index 9d51ce6bab..09e13b450c 100644 --- a/resource_detectors/README.md +++ b/resource_detectors/README.md @@ -69,6 +69,7 @@ or inaccessible. | `process.executable.build_id.htlhash` | Deterministic SHA256-based build ID | Yes | No | Yes | Limitations: + - `process.executable.path`, `process.executable.name`, and `process.executable.build_id.htlhash` are not populated on macOS because reading `/proc//exe` is not available. A macOS implementation via From c3d5ab8348b492c868ce6e10b25033385d95378b Mon Sep 17 00:00:00 2001 From: Pradeep Date: Sat, 22 Aug 2026 08:51:48 +0530 Subject: [PATCH 14/24] fix:CI type failure --- resource_detectors/src/process_detector_utils.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index e41c7140c8..9f4a7bf3a4 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -313,7 +313,7 @@ std::string GetProcessCreationTime(const int32_t &pid) char buf[32]; std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03lluZ", utc_time.tm_year + 1900, utc_time.tm_mon + 1, utc_time.tm_mday, utc_time.tm_hour, utc_time.tm_min, - utc_time.tm_sec, start_msecs); + utc_time.tm_sec, static_cast(start_msecs)); return std::string(buf); #endif } From d7daad124dbf13f81535ddbc14937e223c93cc08 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Sat, 22 Aug 2026 18:56:08 +0530 Subject: [PATCH 15/24] fix: CI failure- increase buff size --- resource_detectors/src/process_detector_utils.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 9f4a7bf3a4..ec4bfc8a2b 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -175,7 +175,7 @@ std::string FileTimeToIso8601(const FILETIME &ft) { return std::string(); } - char buf[32]; + char buf[128]; std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", static_cast(st.wYear), static_cast(st.wMonth), static_cast(st.wDay), static_cast(st.wHour), static_cast(st.wMinute), static_cast(st.wSecond), @@ -275,7 +275,7 @@ std::string GetProcessCreationTime(const int32_t &pid) int64_t usecs = kp.kp_proc.p_starttime.tv_usec; struct tm utc_time = {}; gmtime_r(&secs, &utc_time); - char buf[32]; + char buf[128]; std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03ldZ", utc_time.tm_year + 1900, utc_time.tm_mon + 1, utc_time.tm_mday, utc_time.tm_hour, utc_time.tm_min, utc_time.tm_sec, usecs / 1000); @@ -310,7 +310,7 @@ std::string GetProcessCreationTime(const int32_t &pid) struct tm utc_time = {}; gmtime_r(&t, &utc_time); - char buf[32]; + char buf[128]; std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03lluZ", utc_time.tm_year + 1900, utc_time.tm_mon + 1, utc_time.tm_mday, utc_time.tm_hour, utc_time.tm_min, utc_time.tm_sec, static_cast(start_msecs)); From 02f132d36dd1ed12d0c121b4860c97a9d574c593 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Sat, 22 Aug 2026 20:16:37 +0530 Subject: [PATCH 16/24] fix: cppcheck containerOutofBounds warning --- resource_detectors/src/process_detector_utils.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index ec4bfc8a2b..12eeaf3826 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -68,6 +68,7 @@ ExecutableInfo GetExecutableInfo(const int32_t &pid) return info; } std::string utf8_path(size_needed, 0); + // cppcheck-suppress containerOutOfBounds WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, &utf8_path[0], size_needed, NULL, NULL); info.path = utf8_path; @@ -130,8 +131,9 @@ std::vector GetCommandWithArgs(const int32_t &pid) int size_needed = WideCharToMultiByte(CP_UTF8, 0, argvW[i], -1, NULL, 0, NULL, NULL); if (size_needed > 0) { - std::string arg(size_needed - 1, 0); + std::string arg(size_needed, 0); WideCharToMultiByte(CP_UTF8, 0, argvW[i], -1, &arg[0], size_needed, NULL, NULL); + arg.resize(size_needed - 1); args.push_back(arg); } } @@ -367,8 +369,9 @@ std::string GetProcessOwner() { return std::string(); } - std::string utf8_name(size_needed - 1, '\0'); + std::string utf8_name(size_needed, '\0'); WideCharToMultiByte(CP_UTF8, 0, name, -1, &utf8_name[0], size_needed, nullptr, nullptr); + utf8_name.resize(size_needed - 1); return utf8_name; #else From a27adf3abf3fe46d1eb935369ea8e73f9f9dcd2b Mon Sep 17 00:00:00 2001 From: Pradeep Date: Sun, 23 Aug 2026 00:30:00 +0530 Subject: [PATCH 17/24] fix: merge duplication --- resource_detectors/src/process_detector_utils.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 7b3ca7976c..2939a971aa 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -27,7 +27,6 @@ #ifdef __APPLE__ # include -# include #endif #ifndef _MSC_VER From 54cf114b226321a02d0854db428c4d2992b1470c Mon Sep 17 00:00:00 2001 From: Pradeep Date: Sun, 23 Aug 2026 01:02:46 +0530 Subject: [PATCH 18/24] fix: service_detector_utils stale call --- .../src/service_detector_utils.cc | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/resource_detectors/src/service_detector_utils.cc b/resource_detectors/src/service_detector_utils.cc index 3a45bb72c6..476052f455 100644 --- a/resource_detectors/src/service_detector_utils.cc +++ b/resource_detectors/src/service_detector_utils.cc @@ -73,20 +73,9 @@ std::string GetServiceName() return service_name; } - const std::string executable_path = GetExecutablePath(static_cast(getpid())); - std::string executable_name; - if (!executable_path.empty()) - { - const size_t pos = executable_path.find_last_of("/\\"); - if (pos == std::string::npos) - { - executable_name = executable_path; - } - else - { - executable_name = executable_path.substr(pos + 1); - } - } + const auto exe_info = GetExecutableInfo(static_cast(getpid())); + const std::string &executable_name = exe_info.name; + if (!executable_name.empty()) { std::string fallback_service_name(kUnknownServicePrefix); From 2cf5a0f4aa03e544c6f2b32040e0cce0a1fdf5b1 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Mon, 24 Aug 2026 07:29:54 +0530 Subject: [PATCH 19/24] fix: add head and tail processing with overlap in htlHash --- resource_detectors/README.md | 6 +++++- .../detail/process_detector_utils.h | 2 ++ .../src/process_detector_utils.cc | 19 +++++++++---------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/resource_detectors/README.md b/resource_detectors/README.md index 456133ca4b..1c2819fb96 100644 --- a/resource_detectors/README.md +++ b/resource_detectors/README.md @@ -88,7 +88,11 @@ or inaccessible. Limitations: -- `process.executable.build_id.htlhash` is not populated on macOS. +- `process.executable.build_id.htlhash` is not populated on macOS because the + executable binary cannot be read from its path on that platform. +- For executables smaller than 4096 bytes the head and tail slices of the + htlhash algorithm overlap (both cover the entire file), which is correct per + the [spec](https://opentelemetry.io/docs/specs/semconv/attributes-registry/process/#algorithm-for-processexecutablebuild_idhtlhash). ### Env Entity Resource Detector (Experimental) diff --git a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h index 7fd55d50a1..65003b45d0 100644 --- a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h +++ b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h @@ -84,6 +84,8 @@ std::string GetProcessOwner(); /** * Computes the deterministic htlhash build ID for the process executable. * Algorithm: SHA256(File[:4096] || File[-4096:] || BigEndianUInt64(FileLen)) + * For files <= 4096 bytes the two slices overlap (both equal the whole file), + * matching the spec requirement that inputs are "not padded". * The result is the first 16 bytes (128 bits) of the digest as a lowercase hex string. * Returns an empty string if the executable cannot be read. * diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 2939a971aa..942333cabb 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -587,17 +587,16 @@ std::string GetExecutableBuildIdHtlhash(const int32_t &pid) std::size_t head_read = static_cast(f.gcount()); head.resize(head_read); - // Read tail (up to 4096 bytes from end) only if file is larger than 4096 bytes. + // Read tail (up to 4096 bytes from end). For files <= 4096 bytes the tail + // overlaps the head (both cover the whole file), matching the spec. std::string tail; - if (file_size > kChunkSize) - { - tail.resize(kChunkSize, '\0'); - std::size_t tail_offset = static_cast(file_size - kChunkSize); - f.seekg(static_cast(tail_offset), std::ios::beg); - f.read(&tail[0], static_cast(kChunkSize)); - std::size_t tail_read = static_cast(f.gcount()); - tail.resize(tail_read); - } + tail.resize(kChunkSize, '\0'); + std::size_t tail_offset = + (file_size < kChunkSize) ? 0 : static_cast(file_size - kChunkSize); + f.seekg(static_cast(tail_offset), std::ios::beg); + f.read(&tail[0], static_cast(kChunkSize)); + std::size_t tail_read = static_cast(f.gcount()); + tail.resize(tail_read); // Encode file length as big-endian uint64. std::uint64_t file_size_be = file_size; From 426c88819780a6b1366dc0323d82eca2250a5d79 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Mon, 24 Aug 2026 07:48:50 +0530 Subject: [PATCH 20/24] fix: Readme and tests update for macOS htlHash --- resource_detectors/README.md | 8 +++++--- resource_detectors/src/process_detector_utils.cc | 6 ++++-- resource_detectors/test/process_detector_test.cc | 6 +++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/resource_detectors/README.md b/resource_detectors/README.md index 1c2819fb96..144edb36e7 100644 --- a/resource_detectors/README.md +++ b/resource_detectors/README.md @@ -84,12 +84,14 @@ or inaccessible. | `process.executable.name` | Basename of the executable path | Yes | Yes | Yes | | `process.creation.time` | Process start time in ISO 8601 UTC | Yes | Yes | Yes | | `process.owner` | Username of the process owner | Yes | Yes | Yes | -| `process.executable.build_id.htlhash` | Deterministic SHA256-based build ID | Yes | No | Yes | +| `process.executable.build_id.htlhash` | Deterministic SHA256-based build ID | Yes | Yes | Yes | Limitations: -- `process.executable.build_id.htlhash` is not populated on macOS because the - executable binary cannot be read from its path on that platform. +- On macOS, `process.executable.path`, `process.executable.name`, and + `process.executable.build_id.htlhash` are resolved via `_NSGetExecutablePath()`, + which only works for the **current process**. These attributes are always + populated for the running process, but cannot be resolved for an arbitrary PID. - For executables smaller than 4096 bytes the head and tail slices of the htlhash algorithm overlap (both cover the entire file), which is correct per the [spec](https://opentelemetry.io/docs/specs/semconv/attributes-registry/process/#algorithm-for-processexecutablebuild_idhtlhash). diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 942333cabb..4a9acc2485 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -73,8 +73,10 @@ ExecutableInfo GetExecutableInfo(const int32_t &pid) } std::string utf8_path(size_needed, 0); // cppcheck-suppress containerOutOfBounds - WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, &utf8_path[0], size_needed, NULL, NULL); - + if (WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, &utf8_path[0], size_needed, NULL, NULL) <= 0) + { + return info; + } info.path = utf8_path; #elif defined(__APPLE__) char path[4096]; diff --git a/resource_detectors/test/process_detector_test.cc b/resource_detectors/test/process_detector_test.cc index e67ef64a2f..de547395bf 100644 --- a/resource_detectors/test/process_detector_test.cc +++ b/resource_detectors/test/process_detector_test.cc @@ -332,8 +332,8 @@ TEST(ProcessResourceDetectorTest, DetectPopulatesExpectedAttributes) EXPECT_NE(attrs.find(opentelemetry::semconv::process::kProcessPid), attrs.end()) << "process.pid must be present"; -#if defined(_MSC_VER) || defined(__linux__) - // process.executable.path — present on Linux and Windows. +#if defined(_MSC_VER) || defined(__linux__) || defined(__APPLE__) + // process.executable.path — present on Linux, macOS, and Windows. EXPECT_NE(attrs.find(opentelemetry::semconv::process::kProcessExecutablePath), attrs.end()) << "process.executable.path must be present on this platform"; @@ -341,7 +341,7 @@ TEST(ProcessResourceDetectorTest, DetectPopulatesExpectedAttributes) EXPECT_NE(attrs.find(opentelemetry::semconv::process::kProcessExecutableName), attrs.end()) << "process.executable.name must be present on this platform"; - // process.executable.build_id.htlhash — present on Linux and Windows. + // process.executable.build_id.htlhash — present on Linux, macOS, and Windows. EXPECT_NE(attrs.find(opentelemetry::semconv::process::kProcessExecutableBuildIdHtlhash), attrs.end()) << "process.executable.build_id.htlhash must be present on this platform"; From 5d5ca4c701287190cbb990b655bf9695ffdda695 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Mon, 24 Aug 2026 08:00:45 +0530 Subject: [PATCH 21/24] fix: -Wformat warning --- resource_detectors/src/process_detector_utils.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 4a9acc2485..6549a15555 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -292,7 +292,7 @@ std::string GetProcessCreationTime(const int32_t &pid) struct tm utc_time = {}; gmtime_r(&secs, &utc_time); char buf[128]; - std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03ldZ", utc_time.tm_year + 1900, + std::snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03lldZ", utc_time.tm_year + 1900, utc_time.tm_mon + 1, utc_time.tm_mday, utc_time.tm_hour, utc_time.tm_min, utc_time.tm_sec, usecs / 1000); return std::string(buf); From e70971d5f8a4fc30acb1d1a585d502effcc39d72 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Mon, 24 Aug 2026 21:51:40 +0530 Subject: [PATCH 22/24] add ChangeLog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 805c832e50..7dbdd93d25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ Increment the: ## [Unreleased] +* [RESOURCE DETECTOR] Add required and recommended attributes for process entity + [#4437](https://github.com/open-telemetry/opentelemetry-cpp/pull/4437) * [CONFIGURATION] Add a configuration builder for the host resource detector [#4451](https://github.com/open-telemetry/opentelemetry-cpp/issues/4451) * [CONFIGURATION] Build the configured resource detectors in SdkBuilder, apply From 51e6d7c0dc613d7bebdedf05f8bd2790a2891942 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Tue, 25 Aug 2026 09:33:11 +0530 Subject: [PATCH 23/24] update: htlHash uses openssl for SHA256 --- resource_detectors/BUILD | 1 + resource_detectors/CMakeLists.txt | 7 +- .../src/process_detector_utils.cc | 167 +++--------------- 3 files changed, 27 insertions(+), 148 deletions(-) diff --git a/resource_detectors/BUILD b/resource_detectors/BUILD index e0a715f55b..c580e47af2 100644 --- a/resource_detectors/BUILD +++ b/resource_detectors/BUILD @@ -23,6 +23,7 @@ cc_library( "//resource_detectors:headers", "//sdk:headers", "//sdk/src/resource", + "@boringssl//:crypto", ], ) diff --git a/resource_detectors/CMakeLists.txt b/resource_detectors/CMakeLists.txt index 02c0d88c28..62250545fc 100644 --- a/resource_detectors/CMakeLists.txt +++ b/resource_detectors/CMakeLists.txt @@ -5,6 +5,8 @@ # opentelemetry_container_resource_detector # +find_package(OpenSSL REQUIRED) + add_library(opentelemetry_container_resource_detector src/container_detector.cc src/container_detector_utils.cc) @@ -23,6 +25,8 @@ target_include_directories( # opentelemetry_container_resource_detector_builder # +find_package(OpenSSL REQUIRED) + add_library(opentelemetry_container_resource_detector_builder src/container_detector_builder.cc) @@ -109,7 +113,8 @@ set_target_properties(opentelemetry_process_resource_detector set_target_version(opentelemetry_process_resource_detector) target_link_libraries(opentelemetry_process_resource_detector - PUBLIC opentelemetry_resources) + PUBLIC opentelemetry_resources + PRIVATE OpenSSL::Crypto) target_include_directories( opentelemetry_process_resource_detector PUBLIC "$" diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 6549a15555..67029ca145 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -9,6 +9,9 @@ #include #include +#include +#include + #if defined(__APPLE__) # include #endif @@ -409,140 +412,6 @@ std::string GetProcessOwner() namespace { -// Minimal self-contained SHA-256 implementation. -// Reference: FIPS 180-4 -struct Sha256Context -{ - uint32_t state[8] = {0}; - uint64_t bit_count = 0; - uint8_t buffer[64] = {0}; - uint32_t buffer_len = 0; -}; - -static const uint32_t kSha256K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; - -inline uint32_t Rotr32(uint32_t x, int n) -{ - return (x >> n) | (x << (32 - n)); -} - -void Sha256ProcessBlock(Sha256Context &ctx, const uint8_t block[64]) -{ - uint32_t w[64]; - for (int i = 0; i < 16; ++i) - { - w[i] = (static_cast(block[i * 4]) << 24) | - (static_cast(block[i * 4 + 1]) << 16) | - (static_cast(block[i * 4 + 2]) << 8) | - (static_cast(block[i * 4 + 3])); - } - for (int i = 16; i < 64; ++i) - { - uint32_t s0 = Rotr32(w[i - 15], 7) ^ Rotr32(w[i - 15], 18) ^ (w[i - 15] >> 3); - uint32_t s1 = Rotr32(w[i - 2], 17) ^ Rotr32(w[i - 2], 19) ^ (w[i - 2] >> 10); - w[i] = w[i - 16] + s0 + w[i - 7] + s1; - } - - uint32_t a = ctx.state[0], b = ctx.state[1], c = ctx.state[2], d = ctx.state[3]; - uint32_t e = ctx.state[4], f = ctx.state[5], g = ctx.state[6], h = ctx.state[7]; - - for (int i = 0; i < 64; ++i) - { - uint32_t S1 = Rotr32(e, 6) ^ Rotr32(e, 11) ^ Rotr32(e, 25); - uint32_t ch = (e & f) ^ (~e & g); - uint32_t temp1 = h + S1 + ch + kSha256K[i] + w[i]; - uint32_t S0 = Rotr32(a, 2) ^ Rotr32(a, 13) ^ Rotr32(a, 22); - uint32_t maj = (a & b) ^ (a & c) ^ (b & c); - uint32_t temp2 = S0 + maj; - - h = g; - g = f; - f = e; - e = d + temp1; - d = c; - c = b; - b = a; - a = temp1 + temp2; - } - - ctx.state[0] += a; - ctx.state[1] += b; - ctx.state[2] += c; - ctx.state[3] += d; - ctx.state[4] += e; - ctx.state[5] += f; - ctx.state[6] += g; - ctx.state[7] += h; -} - -void Sha256Init(Sha256Context &ctx) -{ - ctx.state[0] = 0x6a09e667; - ctx.state[1] = 0xbb67ae85; - ctx.state[2] = 0x3c6ef372; - ctx.state[3] = 0xa54ff53a; - ctx.state[4] = 0x510e527f; - ctx.state[5] = 0x9b05688c; - ctx.state[6] = 0x1f83d9ab; - ctx.state[7] = 0x5be0cd19; - ctx.bit_count = 0; - ctx.buffer_len = 0; -} - -void Sha256Update(Sha256Context &ctx, const uint8_t *data, std::size_t len) -{ - for (std::size_t i = 0; i < len; ++i) - { - ctx.buffer[ctx.buffer_len++] = data[i]; - if (ctx.buffer_len == 64) - { - Sha256ProcessBlock(ctx, ctx.buffer); - ctx.buffer_len = 0; - } - } - ctx.bit_count += static_cast(len) * 8; -} - -void Sha256Final(Sha256Context &ctx, uint8_t digest[32]) -{ - ctx.buffer[ctx.buffer_len++] = 0x80; - if (ctx.buffer_len > 56) - { - while (ctx.buffer_len < 64) - { - ctx.buffer[ctx.buffer_len++] = 0x00; - } - Sha256ProcessBlock(ctx, ctx.buffer); - ctx.buffer_len = 0; - } - while (ctx.buffer_len < 56) - { - ctx.buffer[ctx.buffer_len++] = 0x00; - } - // Append bit count as big-endian 64-bit integer. - for (int i = 7; i >= 0; --i) - { - ctx.buffer[ctx.buffer_len++] = static_cast((ctx.bit_count >> (i * 8)) & 0xFF); - } - Sha256ProcessBlock(ctx, ctx.buffer); - - for (int i = 0; i < 8; ++i) - { - digest[i * 4] = static_cast((ctx.state[i] >> 24) & 0xFF); - digest[i * 4 + 1] = static_cast((ctx.state[i] >> 16) & 0xFF); - digest[i * 4 + 2] = static_cast((ctx.state[i] >> 8) & 0xFF); - digest[i * 4 + 3] = static_cast(ctx.state[i] & 0xFF); - } -} - // Encode the first `byte_count` bytes of `digest` as lowercase hex. std::string DigestToHex(const uint8_t *digest, std::size_t byte_count) { @@ -610,14 +479,16 @@ std::string GetExecutableBuildIdHtlhash(const int32_t &pid) } // SHA256(head || tail || len_bytes). - Sha256Context ctx; - Sha256Init(ctx); - Sha256Update(ctx, reinterpret_cast(head.data()), head.size()); - Sha256Update(ctx, reinterpret_cast(tail.data()), tail.size()); - Sha256Update(ctx, len_bytes, 8); + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr); + EVP_DigestUpdate(ctx, reinterpret_cast(head.data()), head.size()); + EVP_DigestUpdate(ctx, reinterpret_cast(tail.data()), tail.size()); + EVP_DigestUpdate(ctx, len_bytes, 8); - uint8_t digest[32]; - Sha256Final(ctx, digest); + uint8_t digest[EVP_MAX_MD_SIZE]; + unsigned int digest_len = 0; + EVP_DigestFinal_ex(ctx, digest, &digest_len); + EVP_MD_CTX_free(ctx); // Return first 16 bytes (128 bits) as hex (32 hex chars). return DigestToHex(digest, 16); @@ -625,12 +496,14 @@ std::string GetExecutableBuildIdHtlhash(const int32_t &pid) std::string ComputeSha256Hex(const std::string &data) { - Sha256Context ctx; - Sha256Init(ctx); - Sha256Update(ctx, reinterpret_cast(data.data()), data.size()); - - uint8_t digest[32]; - Sha256Final(ctx, digest); + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr); + EVP_DigestUpdate(ctx, reinterpret_cast(data.data()), data.size()); + + uint8_t digest[EVP_MAX_MD_SIZE]; + unsigned int digest_len = 0; + EVP_DigestFinal_ex(ctx, digest, &digest_len); + EVP_MD_CTX_free(ctx); // Return all 32 bytes (256 bits) as hex (64 hex chars). return DigestToHex(digest, 32); From 45a4cc8f75f6e5d3cf1b2ca6cef28aeaf31a001c Mon Sep 17 00:00:00 2001 From: Pradeep Date: Tue, 25 Aug 2026 12:26:51 +0530 Subject: [PATCH 24/24] fix: remove unused import --- resource_detectors/src/process_detector_utils.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 67029ca145..8ca0149120 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -10,7 +10,6 @@ #include #include -#include #if defined(__APPLE__) # include