Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[extension/cgroupruntime]: Initial implementation #35472

Merged
merged 25 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
11bb2f8
feat: add initial files for cgroup runtime extension
rogercoll Sep 18, 2024
87dd22c
refactor: inject runtime modifiers functions
rogercoll Sep 27, 2024
f07341a
Merge branch 'open-telemetry:main' into add_cgroupruntime_extension
rogercoll Sep 27, 2024
83f05d4
refactor: rename enablement configuation options
rogercoll Sep 27, 2024
09c82af
Merge branch 'main' into add_cgroupruntime_extension
rogercoll Oct 30, 2024
e0e6c25
feat: add log entry after runtime modification
rogercoll Nov 5, 2024
b302b72
Merge branch 'main' into add_cgroupruntime_extension
rogercoll Nov 5, 2024
9f93544
chore: update code owner file references
rogercoll Nov 5, 2024
c8b8e3d
fix: lint and changelog
rogercoll Nov 5, 2024
2166b4d
add config testdata tests
rogercoll Nov 5, 2024
e2d2b96
fix: config tests linter
rogercoll Nov 5, 2024
f66cd02
fix: go generate references
rogercoll Nov 5, 2024
dee7791
docs: add extension README
rogercoll Nov 6, 2024
687fc60
Merge branch 'main' into add_cgroupruntime_extension
rogercoll Nov 6, 2024
c64323d
test: add validate error
rogercoll Nov 6, 2024
2035f55
add extension to versions.yaml file
rogercoll Nov 6, 2024
8b189e9
Merge branch 'main' into add_cgroupruntime_extension
rogercoll Nov 8, 2024
0c61613
Merge branch 'main' into add_cgroupruntime_extension
rogercoll Nov 20, 2024
0ee5265
chore: fix go mod tidy
rogercoll Nov 20, 2024
4f485cf
Merge branch 'main' into add_cgroupruntime_extension
rogercoll Nov 22, 2024
1f0c26f
fix: go generate docs change
rogercoll Nov 22, 2024
21c689e
Update extension/cgroupruntimeextension/README.md
rogercoll Nov 26, 2024
51d1de9
Update extension/cgroupruntimeextension/README.md
rogercoll Nov 26, 2024
6abcf49
feat: disable zero ratio values
rogercoll Nov 26, 2024
b0061bc
Merge branch 'main' into add_cgroupruntime_extension
rogercoll Nov 26, 2024
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
27 changes: 27 additions & 0 deletions .chloggen/add_cgroupruntime_extension.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: new_component

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: extension/cgroupruntime

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Initial implementation for cgroupruntime extension.

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

# (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: []
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ extension/asapauthextension/ @open-telemetry/collector-cont
extension/awsproxy/ @open-telemetry/collector-contrib-approvers @Aneurysm9 @mxiamxia
extension/basicauthextension/ @open-telemetry/collector-contrib-approvers @jpkrohling @frzifus
extension/bearertokenauthextension/ @open-telemetry/collector-contrib-approvers @jpkrohling @frzifus
extension/cgroupruntimeextension/ @open-telemetry/collector-contrib-approvers @mx-psi @rogercoll
extension/encoding/ @open-telemetry/collector-contrib-approvers @atoulme @dao-jun @dmitryax @MovieStoreGuy @VihasMakwana
extension/encoding/avrologencodingextension/ @open-telemetry/collector-contrib-approvers @thmshmm
extension/encoding/jaegerencodingextension/ @open-telemetry/collector-contrib-approvers @MovieStoreGuy @atoulme
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ body:
- extension/awsproxy
- extension/basicauth
- extension/bearertokenauth
- extension/cgroupruntime
- extension/encoding
- extension/encoding/avrologencoding
- extension/encoding/jaegerencoding
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ body:
- extension/awsproxy
- extension/basicauth
- extension/bearertokenauth
- extension/cgroupruntime
- extension/encoding
- extension/encoding/avrologencoding
- extension/encoding/jaegerencoding
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/other.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ body:
- extension/awsproxy
- extension/basicauth
- extension/bearertokenauth
- extension/cgroupruntime
- extension/encoding
- extension/encoding/avrologencoding
- extension/encoding/jaegerencoding
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/unmaintained.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ body:
- extension/awsproxy
- extension/basicauth
- extension/bearertokenauth
- extension/cgroupruntime
- extension/encoding
- extension/encoding/avrologencoding
- extension/encoding/jaegerencoding
Expand Down
1 change: 1 addition & 0 deletions extension/cgroupruntimeextension/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../../Makefile.Common
42 changes: 42 additions & 0 deletions extension/cgroupruntimeextension/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Cgroup Go runtime extension


<!-- status autogenerated section -->
| Status | |
| ------------- |-----------|
| Stability | [development] |
| Distributions | [contrib] |
| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aextension%2Fcgroupruntime%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aextension%2Fcgroupruntime) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aextension%2Fcgroupruntime%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aextension%2Fcgroupruntime) |
| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@mx-psi](https://www.github.com/mx-psi), [@rogercoll](https://www.github.com/rogercoll) |

[development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development
[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib
<!-- end autogenerated section -->

## Overview

The OpenTelemetry CGroup Auto-Config Extension is designed to optimize Go runtime performance in containerized environments by automatically configuring GOMAXPROCS and GOMEMLIMIT based on the Linux cgroup filesystem. This extension leverages [automaxprocs](https://github.com/uber-go/automaxprocs) and [automemlimit](https://github.com/KimMachineGun/automemlimit) packages to dynamically adjust Go runtime variables, ensuring efficient resource usage aligned with container limits.
rogercoll marked this conversation as resolved.
Show resolved Hide resolved

## Configuration

The following settings can be configured:

- `gomaxprocs`: Configures the behavior of setting `GOMAXPROCS`, the maximum number of CPUs for Go runtime. Options:
- `enabled`: A boolean value to enable or disable automatic configuration of `GOMAXPROCS` based on the system’s cgroup settings (default: true).

- `gomemlimit`: Configures the behavior of setting `GOMEMLIMIT`, the maximum memory limit for Go runtime. Options:
- `enabled`: A boolean value to enable or disable automatic configuration of `GOMEMLIMIT` (default: true).
- `ratio`: A floating-point value between 0 and 1 that represents the fraction of the detected memory limit to allocate for the Go runtime (default: 0.9).

## Examples

```yaml
extension:
# processor name: cgroupruntime
cgroupruntime:
gomaxprocs:
enable: true
gomemlimit:
enable: true
rogercoll marked this conversation as resolved.
Show resolved Hide resolved
ratio: 0.8
```
28 changes: 28 additions & 0 deletions extension/cgroupruntimeextension/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package cgroupruntimeextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/cgroupruntimeextension"

import "errors" // Config contains the configuration for the cgroup runtime extension.

type Config struct {
GoMaxProcs GoMaxProcsConfig `mapstructure:"gomaxprocs"`
GoMemLimit GoMemLimitConfig `mapstructure:"gomemlimit"`
}

type GoMaxProcsConfig struct {
Enabled bool `mapstructure:"enabled"`
}

type GoMemLimitConfig struct {
Enabled bool `mapstructure:"enabled"`
Ratio float64 `mapstructure:"ratio"`
}

// Validate checks if the extension configuration is valid
func (cfg *Config) Validate() error {
if cfg.GoMemLimit.Ratio < 0 || cfg.GoMemLimit.Ratio > 1 {
return errors.New("gomemlimit ratio must be between 0 and 1")
mx-psi marked this conversation as resolved.
Show resolved Hide resolved
}
return nil
}
73 changes: 73 additions & 0 deletions extension/cgroupruntimeextension/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package cgroupruntimeextension

import (
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/confmap/confmaptest"

"github.com/open-telemetry/opentelemetry-collector-contrib/extension/cgroupruntimeextension/internal/metadata"
)

func TestLoadConfig(t *testing.T) {
t.Parallel()

tests := []struct {
id component.ID
expected component.Config
unmarshalErrorMessage string
validateErrorMessage string
}{
{
id: component.NewID(metadata.Type),
expected: &Config{
GoMaxProcs: GoMaxProcsConfig{Enabled: true},
GoMemLimit: GoMemLimitConfig{
Enabled: true,
Ratio: 0.9,
},
},
},
{
id: component.NewIDWithName(metadata.Type, "invalid_ratio"),
validateErrorMessage: "gomemlimit ratio must be between 0 and 1",
},
{
id: component.NewIDWithName(metadata.Type, "invalid_ratio_type"),
unmarshalErrorMessage: "decoding failed due to the following error(s):\n\n'gomemlimit.ratio' expected type 'float64', got unconvertible type 'string', value: 'not_valid'",
},
}

for _, tt := range tests {
t.Run(tt.id.String(), func(t *testing.T) {
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml"))
require.NoError(t, err)

factory := NewFactory()
cfg := factory.CreateDefaultConfig()

sub, err := cm.Sub(tt.id.String())
require.NoError(t, err)

if tt.unmarshalErrorMessage != "" {
assert.ErrorContains(t, sub.Unmarshal(cfg), tt.unmarshalErrorMessage)
return
}
require.NoError(t, sub.Unmarshal(cfg))

if tt.validateErrorMessage != "" {
assert.EqualError(t, component.ValidateConfig(cfg), tt.validateErrorMessage)
return
}

assert.NoError(t, component.ValidateConfig(cfg))
assert.Equal(t, tt.expected, cfg)
})
}
}
6 changes: 6 additions & 0 deletions extension/cgroupruntimeextension/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

//go:generate mdatagen metadata.yaml

package cgroupruntimeextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/cgroupruntimeextension"
77 changes: 77 additions & 0 deletions extension/cgroupruntimeextension/extension.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package cgroupruntimeextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/cgroupruntimeextension"

import (
"context"
"runtime"
"runtime/debug"

"go.opentelemetry.io/collector/component"
"go.uber.org/zap"
)

type (
undoFunc func()
maxProcsFn func() (undoFunc, error)
memLimitWithRatioFn func(float64) (undoFunc, error)
)

type cgroupRuntimeExtension struct {
config *Config
logger *zap.Logger

// runtime modifiers
maxProcsFn
undoMaxProcsFn undoFunc

memLimitWithRatioFn
undoMemLimitFn undoFunc
}

func newCgroupRuntime(cfg *Config, logger *zap.Logger, maxProcsFn maxProcsFn, memLimitFn memLimitWithRatioFn) *cgroupRuntimeExtension {
return &cgroupRuntimeExtension{
config: cfg,
logger: logger,
maxProcsFn: maxProcsFn,
memLimitWithRatioFn: memLimitFn,
}
}

func (c *cgroupRuntimeExtension) Start(_ context.Context, _ component.Host) error {
var err error
if c.config.GoMaxProcs.Enabled {
c.undoMaxProcsFn, err = c.maxProcsFn()
if err != nil {
return err
}

c.logger.Info("GOMAXPROCS has been set",
zap.Int("GOMAXPROCS", runtime.GOMAXPROCS(-1)),
)
}

if c.config.GoMemLimit.Enabled {
c.undoMemLimitFn, err = c.memLimitWithRatioFn(c.config.GoMemLimit.Ratio)
if err != nil {
return err
}

c.logger.Info("GOMEMLIMIT has been set",
zap.Int64("GOMEMLIMIT", debug.SetMemoryLimit(-1)),
)
}
return nil
}

func (c *cgroupRuntimeExtension) Shutdown(_ context.Context) error {
if c.undoMaxProcsFn != nil {
c.undoMaxProcsFn()
}
if c.undoMemLimitFn != nil {
c.undoMemLimitFn()
}

return nil
}
67 changes: 67 additions & 0 deletions extension/cgroupruntimeextension/extension_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package cgroupruntimeextension

import (
"context"
"testing"

"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/component/componenttest"
"go.opentelemetry.io/collector/extension/extensiontest"
)

func TestExtension(t *testing.T) {
tests := []struct {
name string
config *Config
expectedCalls int
}{
{
name: "all enabled",
config: &Config{
GoMaxProcs: GoMaxProcsConfig{
Enabled: true,
},
GoMemLimit: GoMemLimitConfig{
Enabled: true,
Ratio: 0.5,
},
},
expectedCalls: 4,
},
{
name: "everything disabled",
config: &Config{
GoMaxProcs: GoMaxProcsConfig{
Enabled: false,
},
GoMemLimit: GoMemLimitConfig{
Enabled: false,
},
},
expectedCalls: 0,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
allCalls := 0
var _err error
setterMock := func() (undoFunc, error) {
allCalls++
return func() { allCalls++ }, _err
}
settings := extensiontest.NewNopSettings()
cg := newCgroupRuntime(test.config, settings.Logger, setterMock, func(_ float64) (undoFunc, error) { return setterMock() })
ctx := context.Background()

err := cg.Start(ctx, componenttest.NewNopHost())
require.NoError(t, err)

require.NoError(t, cg.Shutdown(ctx))
require.Equal(t, test.expectedCalls, allCalls)
})
}
}
Loading