Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/OpenTelemetry.Resources.Process/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## Unreleased

* Extended `ProcessDetector` to include `process.executable.path`,
`process.working_directory`, `process.args_count`,`process.creation.time`,
`process.executable.name`, `process.interactive` as well as `process.title`
as per the latest OpenTelemetry Semantic Convention resource/entity definition.
([#2971](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3347))
Comment on lines +5 to +9
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Extended `ProcessDetector` to include `process.executable.path`,
`process.working_directory`, `process.args_count`,`process.creation.time`,
`process.executable.name`, `process.interactive` as well as `process.title`
as per the latest OpenTelemetry Semantic Convention resource/entity definition.
([#2971](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3347))
* Extended `ProcessDetector` to include `process.executable.path`,
`process.working_directory`, `process.args_count`,`process.creation.time`,
`process.executable.name`, `process.interactive` as well as `process.title`
as per the latest OpenTelemetry Semantic Convention resource definition.
([#3347](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3347))


## 1.14.0-beta.1

Released 2025-Nov-13
Expand Down
37 changes: 29 additions & 8 deletions src/OpenTelemetry.Resources.Process/ProcessDetector.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using System.ComponentModel;

namespace OpenTelemetry.Resources.Process;

/// <summary>
Expand All @@ -14,20 +16,39 @@ internal sealed class ProcessDetector : IResourceDetector
/// <returns>Resource with key-value pairs of resource attributes.</returns>
public Resource Detect()
{
return new Resource(new List<KeyValuePair<string, object>>(2)
using var currentProcess = System.Diagnostics.Process.GetCurrentProcess();

if (currentProcess.HasExited)
{
return Resource.Empty;
}

var attributes = new List<KeyValuePair<string, object>>(9)
{
new(ProcessSemanticConventions.AttributeProcessOwner, Environment.UserName),
new(ProcessSemanticConventions.AttributeProcessArgsCount, Environment.GetCommandLineArgs().Length),
new(ProcessSemanticConventions.AttributeProcessTitle, currentProcess.MainWindowTitle),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if it should be used here. Main windows title is not the process title. Check https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.mainwindowtitle?view=net-10.0

It is recommended attribute, so it can be omitted in this PR.

new(ProcessSemanticConventions.AttributeProcessWorkingDir, Environment.CurrentDirectory),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based what on I see is not reliable and might change in time.
alternative approach currentProcess.StartInfo.WorkingDirectory is not working while I was testing.

As it is conditionally required and we have AttributeProcessArgsCount, I would drop this attribute.


new(ProcessSemanticConventions.AttributeProcessExecName, currentProcess.ProcessName),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that it met SHOULD criteria from OTel sem. conv?
The name of the process executable. On Linux based systems, this SHOULD be set to the base name of the target of /proc/[pid]/exe. On Windows, this SHOULD be set to the base name of GetProcessImageFileNameW.

If not, it is conditionally required, and we have non-controversial in place AttributeProcessArgsCount. Potentially, it can be removed from this PR.

new(ProcessSemanticConventions.AttributeProcessInteractive, Environment.UserInteractive),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that
https://learn.microsoft.com/en-us/dotnet/api/system.environment.userinteractive?view=net-10.0
is compliant with sem conf description: Whether the process is connected to an interactive shell.?

It can be omitted, as it is recommended attribute.

#if NET
new(ProcessSemanticConventions.AttributeProcessPid, Environment.ProcessId),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You already have currentProcess.Id here. Is there any reason to go through Environment and potentially fetching process data from the scratch?

What is more, there will be common scenario both for .NET/non .NET

});
new(ProcessSemanticConventions.AttributeProcessExecPath, Environment.ProcessPath ?? string.Empty),
};
#else
new(ProcessSemanticConventions.AttributeProcessPid, GetProcessPid()),
});
static int GetProcessPid()
new(ProcessSemanticConventions.AttributeProcessPid, currentProcess.Id),
};
#endif

try
{
using var process = System.Diagnostics.Process.GetCurrentProcess();
return process.Id;
attributes.Add(new(ProcessSemanticConventions.AttributeProcessStartTime, currentProcess.StartTime.ToString("O")));
}
#endif
catch (Win32Exception)
{
}

return new Resource(attributes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,11 @@ internal static class ProcessSemanticConventions
{
public const string AttributeProcessOwner = "process.owner";
public const string AttributeProcessPid = "process.pid";
public const string AttributeProcessExecPath = "process.executable.path";
public const string AttributeProcessWorkingDir = "process.working_directory";
public const string AttributeProcessArgsCount = "process.args_count";
public const string AttributeProcessStartTime = "process.creation.time";
public const string AttributeProcessExecName = "process.executable.name";
public const string AttributeProcessInteractive = "process.interactive";
public const string AttributeProcessTitle = "process.title";
}
4 changes: 3 additions & 1 deletion src/OpenTelemetry.Resources.Process/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ using var loggerFactory = LoggerFactory.Create(builder =>
The resource detectors will record the following metadata based on where
your application is running:

- **ProcessDetector**: `process.owner`, `process.pid`.
- **ProcessDetector**: `process.owner`, `process.pid`, `process.executable.path`,
`process.working_directory`, `process.args_count`,`process.creation.time`,
`process.executable.name`, `process.interactive`, `process.title`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lack of info that process.executable.name is avaialbe only on .NET


## References

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,23 @@ public void TestProcessAttributes()
var resource = ResourceBuilder.CreateEmpty().AddProcessDetector().Build();

var resourceAttributes = resource.Attributes.ToDictionary(x => x.Key, x => x.Value);
#if NET
Assert.Equal(9, resourceAttributes.Count);
#else
Assert.Equal(8, resourceAttributes.Count);
#endif

Assert.Equal(2, resourceAttributes.Count);

Assert.IsType<long>(resourceAttributes[ProcessSemanticConventions.AttributeProcessArgsCount]);
Assert.IsType<string>(resourceAttributes[ProcessSemanticConventions.AttributeProcessExecName]);
#if NET
Assert.IsType<string>(resourceAttributes[ProcessSemanticConventions.AttributeProcessExecPath]);
#endif
Assert.IsType<bool>(resourceAttributes[ProcessSemanticConventions.AttributeProcessInteractive]);
Assert.IsType<string>(resourceAttributes[ProcessSemanticConventions.AttributeProcessOwner]);
Assert.IsType<long>(resourceAttributes[ProcessSemanticConventions.AttributeProcessPid]);

Assert.IsType<string>(resourceAttributes[ProcessSemanticConventions.AttributeProcessStartTime]);
Assert.IsType<string>(resourceAttributes[ProcessSemanticConventions.AttributeProcessTitle]);
Assert.IsType<string>(resourceAttributes[ProcessSemanticConventions.AttributeProcessWorkingDir]);
}
}