Skip to content

Commit

Permalink
[receiver/hostmetrics/scrapers/process]: add configuration option to …
Browse files Browse the repository at this point in the history
…mute `error reading username for process` (open-telemetry#28661)

**Description:**

add configuration option `mute_process_user_error`) to mute `error
reading username for process`

**Link to tracking Issue:**

* open-telemetry#14311
* open-telemetry#17187

Signed-off-by: Dominik Rosiek <drosiek@sumologic.com>
  • Loading branch information
sumo-drosiek authored and jmsnll committed Nov 12, 2023
1 parent 416ab97 commit 39db4f3
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 5 deletions.
27 changes: 27 additions & 0 deletions .chloggen/drosiek-mute-process-user-error.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: receiver/hostmetrics/scrapers/process

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: add configuration option to mute `error reading username for process`

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [14311, 17187]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [user]
1 change: 1 addition & 0 deletions receiver/hostmetricsreceiver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ process:
mute_process_name_error: <true|false>
mute_process_exe_error: <true|false>
mute_process_io_error: <true|false>
mute_process_user_error: <true|false>
scrape_process_delay: <time>
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ type Config struct {
// the collector does not have permission to read it's executable path (Linux)
MuteProcessExeError bool `mapstructure:"mute_process_exe_error,omitempty"`

// MuteProcessUserError is a flag that will mute the error encountered when trying to read uid which
// doesn't exist on the system, eg. is owned by user existing in container only
MuteProcessUserError bool `mapstructure:"mute_process_user_error,omitempty"`

// ScrapeProcessDelay is used to indicate the minimum amount of time a process must be running
// before metrics are scraped for it. The default value is 0 seconds (0s)
ScrapeProcessDelay time.Duration `mapstructure:"scrape_process_delay"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,9 @@ func (s *scraper) getProcessMetadata() ([]*processMetadata, error) {

username, err := handle.UsernameWithContext(ctx)
if err != nil {
errs.AddPartial(0, fmt.Errorf("error reading username for process %q (pid %v): %w", executable.name, pid, err))
if !s.config.MuteProcessUserError {
errs.AddPartial(0, fmt.Errorf("error reading username for process %q (pid %v): %w", executable.name, pid, err))
}
}

createTime, err := s.getProcessCreateTime(handle, ctx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -938,8 +938,11 @@ func TestScrapeMetrics_MuteErrorFlags(t *testing.T) {
muteProcessNameError bool
muteProcessExeError bool
muteProcessIOError bool
muteProcessUserError bool
skipProcessNameError bool
omitConfigField bool
expectedError string
expectedCount int
}

testCases := []testCase{
Expand All @@ -948,6 +951,7 @@ func TestScrapeMetrics_MuteErrorFlags(t *testing.T) {
muteProcessNameError: true,
muteProcessExeError: true,
muteProcessIOError: true,
muteProcessUserError: true,
},
{
name: "Process Name Error Muted And Process Exe Error Enabled And Process IO Error Muted",
Expand Down Expand Up @@ -994,6 +998,23 @@ func TestScrapeMetrics_MuteErrorFlags(t *testing.T) {
fmt.Sprintf("error reading process name for pid 1: %v", processNameError)
}(),
},
{
name: "Process User Error Muted",
muteProcessUserError: true,
skipProcessNameError: true,
muteProcessExeError: true,
muteProcessNameError: true,
expectedCount: 4,
},
{
name: "Process User Error Unmuted",
muteProcessUserError: false,
skipProcessNameError: true,
muteProcessExeError: true,
muteProcessNameError: true,
expectedError: fmt.Sprintf("error reading username for process \"processname\" (pid 1): %v", processNameError),
expectedCount: 4,
},
}

for _, test := range testCases {
Expand All @@ -1003,14 +1024,26 @@ func TestScrapeMetrics_MuteErrorFlags(t *testing.T) {
config.MuteProcessNameError = test.muteProcessNameError
config.MuteProcessExeError = test.muteProcessExeError
config.MuteProcessIOError = test.muteProcessIOError
config.MuteProcessUserError = test.muteProcessUserError
}
scraper, err := newProcessScraper(receivertest.NewNopCreateSettings(), config)
require.NoError(t, err, "Failed to create process scraper: %v", err)
err = scraper.start(context.Background(), componenttest.NewNopHost())
require.NoError(t, err, "Failed to initialize process scraper: %v", err)

handleMock := &processHandleMock{}
handleMock.On("NameWithContext", mock.Anything).Return("test", processNameError)
handleMock := newDefaultHandleMock()
if !test.skipProcessNameError {
handleMock.On("NameWithContext", mock.Anything).Return("test", processNameError)
} else {
for _, c := range handleMock.ExpectedCalls {
if c.Method == "UsernameWithContext" {
c.ReturnArguments = []interface{}{"processname", processNameError}
break
}
}
handleMock.On("NameWithContext", mock.Anything).Return("processname", nil)
handleMock.On("CreateTimeWithContext", mock.Anything).Return(time.Now().UnixMilli(), nil)
}
handleMock.On("ExeWithContext", mock.Anything).Return("test", processNameError)
handleMock.On("CmdlineWithContext", mock.Anything).Return("test", processNameError)

Expand All @@ -1023,9 +1056,9 @@ func TestScrapeMetrics_MuteErrorFlags(t *testing.T) {
}
md, err := scraper.scrape(context.Background())

assert.Zero(t, md.MetricCount())
assert.Equal(t, test.expectedCount, md.MetricCount())

if config.MuteProcessNameError && config.MuteProcessExeError {
if config.MuteProcessNameError && config.MuteProcessExeError && config.MuteProcessUserError {
assert.Nil(t, err)
} else {
assert.EqualError(t, err, test.expectedError)
Expand Down

0 comments on commit 39db4f3

Please sign in to comment.