Skip to content

Commit 6e08c5f

Browse files
author
Dominik Rosiek
committed
[receiver/hostmetrics/scrapers/process]: add configuration option to mute error reading username for process
Signed-off-by: Dominik Rosiek <[email protected]>
1 parent 1f646ab commit 6e08c5f

File tree

5 files changed

+72
-5
lines changed

5 files changed

+72
-5
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: receiver/hostmetrics/scrapers/process
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: add configuration option to mute `error reading username for process`
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [14311, 17187]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: [user]

receiver/hostmetricsreceiver/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ process:
118118
mute_process_name_error: <true|false>
119119
mute_process_exe_error: <true|false>
120120
mute_process_io_error: <true|false>
121+
mute_process_user_error: <true|false>
121122
scrape_process_delay: <time>
122123
```
123124

receiver/hostmetricsreceiver/internal/scraper/processscraper/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ type Config struct {
3535
// the collector does not have permission to read it's executable path (Linux)
3636
MuteProcessExeError bool `mapstructure:"mute_process_exe_error,omitempty"`
3737

38+
// MuteProcessUserError is a flag that will mute the error encountered when trying to read uid which
39+
// doesn't exist on the system, eg. is owned by user existing in container only
40+
MuteProcessUserError bool `mapstructure:"mute_process_user_error,omitempty"`
41+
3842
// ScrapeProcessDelay is used to indicate the minimum amount of time a process must be running
3943
// before metrics are scraped for it. The default value is 0 seconds (0s)
4044
ScrapeProcessDelay time.Duration `mapstructure:"scrape_process_delay"`

receiver/hostmetricsreceiver/internal/scraper/processscraper/process_scraper.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,9 @@ func (s *scraper) getProcessMetadata() ([]*processMetadata, error) {
219219

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

225227
createTime, err := s.getProcessCreateTime(handle, ctx)

receiver/hostmetricsreceiver/internal/scraper/processscraper/process_scraper_test.go

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -938,8 +938,11 @@ func TestScrapeMetrics_MuteErrorFlags(t *testing.T) {
938938
muteProcessNameError bool
939939
muteProcessExeError bool
940940
muteProcessIOError bool
941+
muteProcessUserError bool
942+
skipProcessNameError bool
941943
omitConfigField bool
942944
expectedError string
945+
expectedCount int
943946
}
944947

945948
testCases := []testCase{
@@ -948,6 +951,7 @@ func TestScrapeMetrics_MuteErrorFlags(t *testing.T) {
948951
muteProcessNameError: true,
949952
muteProcessExeError: true,
950953
muteProcessIOError: true,
954+
muteProcessUserError: true,
951955
},
952956
{
953957
name: "Process Name Error Muted And Process Exe Error Enabled And Process IO Error Muted",
@@ -994,6 +998,23 @@ func TestScrapeMetrics_MuteErrorFlags(t *testing.T) {
994998
fmt.Sprintf("error reading process name for pid 1: %v", processNameError)
995999
}(),
9961000
},
1001+
{
1002+
name: "Process User Error Muted",
1003+
muteProcessUserError: true,
1004+
skipProcessNameError: true,
1005+
muteProcessExeError: true,
1006+
muteProcessNameError: true,
1007+
expectedCount: 4,
1008+
},
1009+
{
1010+
name: "Process User Error Unmuted",
1011+
muteProcessUserError: false,
1012+
skipProcessNameError: true,
1013+
muteProcessExeError: true,
1014+
muteProcessNameError: true,
1015+
expectedError: fmt.Sprintf("error reading username for process \"processname\" (pid 1): %v", processNameError),
1016+
expectedCount: 4,
1017+
},
9971018
}
9981019

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

1012-
handleMock := &processHandleMock{}
1013-
handleMock.On("NameWithContext", mock.Anything).Return("test", processNameError)
1034+
handleMock := newDefaultHandleMock()
1035+
if !test.skipProcessNameError {
1036+
handleMock.On("NameWithContext", mock.Anything).Return("test", processNameError)
1037+
} else {
1038+
for _, c := range handleMock.ExpectedCalls {
1039+
if c.Method == "UsernameWithContext" {
1040+
c.ReturnArguments = []interface{}{"processname", processNameError}
1041+
break
1042+
}
1043+
}
1044+
handleMock.On("NameWithContext", mock.Anything).Return("processname", nil)
1045+
handleMock.On("CreateTimeWithContext", mock.Anything).Return(time.Now().UnixMilli(), nil)
1046+
}
10141047
handleMock.On("ExeWithContext", mock.Anything).Return("test", processNameError)
10151048
handleMock.On("CmdlineWithContext", mock.Anything).Return("test", processNameError)
10161049

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

1026-
assert.Zero(t, md.MetricCount())
1059+
assert.Equal(t, test.expectedCount, md.MetricCount())
10271060

1028-
if config.MuteProcessNameError && config.MuteProcessExeError {
1061+
if config.MuteProcessNameError && config.MuteProcessExeError && config.MuteProcessUserError {
10291062
assert.Nil(t, err)
10301063
} else {
10311064
assert.EqualError(t, err, test.expectedError)

0 commit comments

Comments
 (0)