mirror of
https://github.com/mattermost/mattermost.git
synced 2026-09-24 16:05:00 +08:00
[MM-67978] Add open file descriptor count to support packet diagnostics (#35834)
* MM-67978: Add open file descriptor count to support packet diagnostics Add OpenFileDescriptors and MaxFileDescriptors fields to SupportPacketDiagnostics.Server. On Linux the open count is read from /proc/self/fd; on macOS from /dev/fd. Both platforms use syscall.Getrlimit(RLIMIT_NOFILE) for the soft limit. Unsupported platforms (e.g. Windows) return -1 for both fields. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> * MM-67978: Move OpenFileDescriptors/MaxFileDescriptors after TotalMemoryMB Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> * fix: guard int64 overflow in getMaxFileDescriptors and update tests for unsupported platforms Add overflow check before casting rlimit.Cur (uint64) to int64 in getMaxFileDescriptors on Linux. Update fd_test.go and support_packet_test.go assertions to accept -1 as a valid sentinel for unsupported platforms instead of requiring a strictly positive value. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * revert: remove unrelated test refactoring from support_packet_test.go Restore the three unrelated changes that crept into this branch: - SetLogRootPathOverride instead of t.Setenv("MM_LOG_PATH", ...) - installTypeOverride field instead of t.Setenv(envVarInstallType, ...) - Restore explanatory comment in TestGetSanitizedConfigFile Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
bfaff4da7e
commit
848ceb3c73
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
//go:build darwin
|
||||
|
||||
package platform
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// getOpenFileDescriptors returns the number of open file descriptors for the current process.
|
||||
func getOpenFileDescriptors() (int64, error) {
|
||||
entries, err := os.ReadDir("/dev/fd")
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
// Subtract 1 because the ReadDir call itself opens a file descriptor that appears in the listing.
|
||||
return max(int64(len(entries))-1, 0), nil
|
||||
}
|
||||
|
||||
// getMaxFileDescriptors returns the soft file descriptor limit for the current process.
|
||||
func getMaxFileDescriptors() (int64, error) {
|
||||
var rlimit syscall.Rlimit
|
||||
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return int64(rlimit.Cur), nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
//go:build linux
|
||||
|
||||
package platform
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// getOpenFileDescriptors returns the number of open file descriptors for the current process.
|
||||
func getOpenFileDescriptors() (int64, error) {
|
||||
entries, err := os.ReadDir("/proc/self/fd")
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
// Subtract 1 because the ReadDir call itself opens a file descriptor that appears in the listing.
|
||||
return max(int64(len(entries))-1, 0), nil
|
||||
}
|
||||
|
||||
// getMaxFileDescriptors returns the soft file descriptor limit for the current process.
|
||||
func getMaxFileDescriptors() (int64, error) {
|
||||
var rlimit syscall.Rlimit
|
||||
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if rlimit.Cur > math.MaxInt64 {
|
||||
return -1, fmt.Errorf("rlimit.Cur %d overflows int64", rlimit.Cur)
|
||||
}
|
||||
return int64(rlimit.Cur), nil
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
//go:build !linux && !darwin
|
||||
|
||||
package platform
|
||||
|
||||
// getOpenFileDescriptors returns -1 on unsupported platforms.
|
||||
func getOpenFileDescriptors() (int64, error) {
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
// getMaxFileDescriptors returns -1 on unsupported platforms.
|
||||
func getMaxFileDescriptors() (int64, error) {
|
||||
return -1, nil
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package platform
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetOpenFileDescriptors(t *testing.T) {
|
||||
count, err := getOpenFileDescriptors()
|
||||
require.NoError(t, err)
|
||||
if count == -1 {
|
||||
return
|
||||
}
|
||||
assert.Positive(t, count)
|
||||
}
|
||||
|
||||
func TestGetMaxFileDescriptors(t *testing.T) {
|
||||
maxFDs, err := getMaxFileDescriptors()
|
||||
require.NoError(t, err)
|
||||
// -1 means unsupported platform; otherwise should be positive
|
||||
assert.True(t, maxFDs == -1 || maxFDs > 0, "maxFDs should be -1 (unsupported) or positive, got %d", maxFDs)
|
||||
}
|
||||
@@ -118,6 +118,14 @@ func (ps *PlatformService) getSupportPacketDiagnostics(rctx request.CTX) (*model
|
||||
installationType = unknownDataPoint
|
||||
}
|
||||
d.Server.InstallationType = installationType
|
||||
d.Server.OpenFileDescriptors, err = getOpenFileDescriptors()
|
||||
if err != nil {
|
||||
rErr = multierror.Append(rErr, errors.Wrap(err, "error while getting open file descriptor count"))
|
||||
}
|
||||
d.Server.MaxFileDescriptors, err = getMaxFileDescriptors()
|
||||
if err != nil {
|
||||
rErr = multierror.Append(rErr, errors.Wrap(err, "error while getting max file descriptor limit"))
|
||||
}
|
||||
d.Server.ProcessID = os.Getpid()
|
||||
|
||||
/* Config */
|
||||
|
||||
@@ -210,6 +210,8 @@ func TestGetSupportPacketDiagnostics(t *testing.T) {
|
||||
assert.Equal(t, "docker", d.Server.InstallationType)
|
||||
assert.Positive(t, d.Server.CPUCores)
|
||||
assert.Positive(t, d.Server.TotalMemoryMB)
|
||||
assert.True(t, d.Server.OpenFileDescriptors == -1 || d.Server.OpenFileDescriptors > 0, "OpenFileDescriptors should be -1 (unsupported) or positive, got %d", d.Server.OpenFileDescriptors)
|
||||
assert.True(t, d.Server.MaxFileDescriptors == -1 || d.Server.MaxFileDescriptors > 0, "MaxFileDescriptors should be -1 (unsupported) or positive, got %d", d.Server.MaxFileDescriptors)
|
||||
assert.Positive(t, d.Server.ProcessID)
|
||||
|
||||
/* Config */
|
||||
|
||||
@@ -25,16 +25,18 @@ type SupportPacketDiagnostics struct {
|
||||
} `yaml:"license"`
|
||||
|
||||
Server struct {
|
||||
OS string `yaml:"os"`
|
||||
Architecture string `yaml:"architecture"`
|
||||
CPUCores int `yaml:"cpu_cores"`
|
||||
TotalMemoryMB uint64 `yaml:"total_memory_mb"`
|
||||
Hostname string `yaml:"hostname"`
|
||||
ProcessID int `yaml:"process_id"`
|
||||
Version string `yaml:"version"`
|
||||
BuildHash string `yaml:"build_hash"`
|
||||
GoVersion string `yaml:"go_version"`
|
||||
InstallationType string `yaml:"installation_type"`
|
||||
OS string `yaml:"os"`
|
||||
Architecture string `yaml:"architecture"`
|
||||
CPUCores int `yaml:"cpu_cores"`
|
||||
TotalMemoryMB uint64 `yaml:"total_memory_mb"`
|
||||
OpenFileDescriptors int64 `yaml:"open_file_descriptors"`
|
||||
MaxFileDescriptors int64 `yaml:"max_file_descriptors"`
|
||||
Hostname string `yaml:"hostname"`
|
||||
ProcessID int `yaml:"process_id"`
|
||||
Version string `yaml:"version"`
|
||||
BuildHash string `yaml:"build_hash"`
|
||||
GoVersion string `yaml:"go_version"`
|
||||
InstallationType string `yaml:"installation_type"`
|
||||
} `yaml:"server"`
|
||||
|
||||
Config struct {
|
||||
|
||||
Reference in New Issue
Block a user