Skip to content
Closed
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
45 changes: 45 additions & 0 deletions changelog/fragments/1766556100-reload-log-level.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# REQUIRED
# Kind can be one of:
# - breaking-change: a change to previously-documented behavior
# - deprecation: functionality that is being removed in a later release
# - bug-fix: fixes a problem in a previous version
# - enhancement: extends functionality but does not break or fix existing behavior
# - feature: new functionality
# - known-issue: problems that we are aware of in a given version
# - security: impacts on the security of a product or a user’s deployment.
# - upgrade: important information for someone upgrading from a prior version
# - other: does not fit into any of the other categories
kind: bug-fix

# REQUIRED for all kinds
# Change summary; a 80ish characters long description of the change.
summary: Fix reloading agent.logging.level for standalone Elastic Agent

# REQUIRED for breaking-change, deprecation, known-issue
# Long description; in case the summary is not enough to describe the change
# this field accommodate a description without length limits.
# description:

# REQUIRED for breaking-change, deprecation, known-issue
# impact:

# REQUIRED for breaking-change, deprecation, known-issue
# action:

# REQUIRED for all kinds
# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc.
component: elastic-agent

# AUTOMATED
# OPTIONAL to manually add other PR URLs
# PR URL: A link the PR that added the changeset.
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
# Please provide it if you are adding a fragment for a different PR.
# pr: https://github.com/owner/repo/1234

# AUTOMATED
# OPTIONAL to manually add other issue URLs
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
# If not present is automatically filled by the tooling with the issue linked to the PR number.
# issue: https://github.com/owner/repo/1234
5 changes: 5 additions & 0 deletions internal/pkg/agent/application/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,20 @@

otelManager, err := otelmanager.NewOTelManager(
log.Named("otel_manager"),
<<<<<<< HEAD

Check failure on line 250 in internal/pkg/agent/application/application.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

expected operand, found '<<' (typecheck)
logLevel, baseLogger,
otelmanager.SubprocessExecutionMode,
=======
logLevel,
baseLogger,
>>>>>>> 85b7e9932 ((bugfix) log level does not change when standalone agent is reloaded or when otel runtime is used (#11998))

Check failure on line 256 in internal/pkg/agent/application/application.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

illegal character U+0023 '#' (typecheck)
agentInfo,
cfg.Settings.Collector,
monitor.ComponentMonitoringConfig,
otelmanager.CollectorStopTimeout,
)
if err != nil {

Check failure on line 262 in internal/pkg/agent/application/application.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

missing ',' in argument list (typecheck)
return nil, nil, nil, fmt.Errorf("failed to create otel manager: %w", err)

Check failure on line 263 in internal/pkg/agent/application/application.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

expected operand, found 'return' (typecheck)
}
coord := coordinator.New(log, cfg, logLevel, agentInfo, specs, reexec, upgrader, runtime, configMgr, varsManager, caps, monitor, isManaged, otelManager, actionAcker, initialUpgradeDetails, compModifiers...)
if managed != nil {
Expand Down
35 changes: 28 additions & 7 deletions internal/pkg/agent/application/coordinator/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,11 @@
Runner

// Update updates the current plain configuration for the otel collector and components.
<<<<<<< HEAD

Check failure on line 144 in internal/pkg/agent/application/coordinator/coordinator.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

syntax error: unexpected <<, expected ~ term or type
Update(*confmap.Conf, []component.Component)

Check failure on line 145 in internal/pkg/agent/application/coordinator/coordinator.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

syntax error: unexpected ] after top level declaration
=======
Update(*confmap.Conf, *monitoringCfg.MonitoringConfig, logp.Level, []component.Component)
>>>>>>> 85b7e9932 ((bugfix) log level does not change when standalone agent is reloaded or when otel runtime is used (#11998))

Check failure on line 148 in internal/pkg/agent/application/coordinator/coordinator.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

invalid character U+0023 '#'

// WatchCollector returns a channel to watch for collector status updates.
WatchCollector() <-chan *status.AggregateStatus
Expand Down Expand Up @@ -1467,10 +1471,20 @@
}
c.currentCfg = currentCfg

if c.vars != nil {
return c.refreshComponentModel(ctx)
// check if log level has changed for standalone elastic-agent
// we'd have to update both the periodic and once config watchers and refactor initialization in application.go to do otherwise.
if c.agentInfo.IsStandalone() {
ll := currentCfg.Settings.LoggingConfig.Level
if ll != c.state.LogLevel {
// set log level for the coordinator
c.setLogLevel(ll)
// set global log level
logger.SetLevel(ll)
c.logger.Infof("log level changed to %s", ll.String())
}
}
return nil

return c.refreshComponentModel(ctx)
}

// Generate the AST for a new incoming configuration and, if successful,
Expand Down Expand Up @@ -1583,10 +1597,13 @@

// Called on the main Coordinator goroutine.
func (c *Coordinator) processLogLevel(ctx context.Context, ll logp.Level) {
c.setLogLevel(ll)
err := c.refreshComponentModel(ctx)
if err != nil {
c.logger.Errorf("updating log level: %s", err.Error())
// do not refresh component model if log level did not change
if c.state.LogLevel != ll {
c.setLogLevel(ll)
err := c.refreshComponentModel(ctx)
if err != nil {
c.logger.Errorf("updating log level: %s", err.Error())
}
}
}

Expand Down Expand Up @@ -1653,7 +1670,11 @@
}
c.logger.With("component_ids", componentIDs).Warn("The Otel runtime manager is HIGHLY EXPERIMENTAL and only intended for testing. Use at your own risk.")
}
<<<<<<< HEAD

Check failure on line 1673 in internal/pkg/agent/application/coordinator/coordinator.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

syntax error: unexpected <<, expected }
c.otelMgr.Update(c.otelCfg, otelModel.Components)
=======
c.otelMgr.Update(c.otelCfg, c.currentCfg.Settings.MonitoringConfig, c.state.LogLevel, otelModel.Components)
>>>>>>> 85b7e9932 ((bugfix) log level does not change when standalone agent is reloaded or when otel runtime is used (#11998))

Check failure on line 1677 in internal/pkg/agent/application/coordinator/coordinator.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

invalid character U+0023 '#') (typecheck)
}

// splitModelBetweenManager splits the model components between the runtime manager and the otel manager.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1401,7 +1401,11 @@ func (f *fakeOTelManager) Errors() <-chan error {
return f.errChan
}

<<<<<<< HEAD
func (f *fakeOTelManager) Update(cfg *confmap.Conf, components []component.Component) {
=======
func (f *fakeOTelManager) Update(cfg *confmap.Conf, monitoring *monitoringCfg.MonitoringConfig, ll logp.Level, components []component.Component) {
>>>>>>> 85b7e9932 ((bugfix) log level does not change when standalone agent is reloaded or when otel runtime is used (#11998))
var collectorResult, componentResult error
if f.updateCollectorCallback != nil {
collectorResult = f.updateCollectorCallback(cfg)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,11 +453,18 @@ func TestCoordinatorReportsInvalidPolicy(t *testing.T) {
}
}()

<<<<<<< HEAD
upgradeMgr, err := upgrade.NewUpgrader(
log,
&artifact.Config{},
&info.AgentInfo{},
)
=======
tmpDir := t.TempDir()
agentInfo, err := info.NewAgentInfo(ctx, false)
require.NoError(t, err)
upgradeMgr, err := upgrade.NewUpgrader(log, &artifact.Config{}, nil, agentInfo, new(upgrade.AgentWatcherHelper), ttl.NewTTLMarkerRegistry(nil, tmpDir))
>>>>>>> 85b7e9932 ((bugfix) log level does not change when standalone agent is reloaded or when otel runtime is used (#11998))
require.NoError(t, err, "errored when creating a new upgrader")

// Channels have buffer length 1, so we don't have to run on multiple
Expand Down Expand Up @@ -490,6 +497,7 @@ func TestCoordinatorReportsInvalidPolicy(t *testing.T) {
ast: emptyAST(t),
componentPIDTicker: time.NewTicker(time.Second * 30),
secretMarkerFunc: testSecretMarkerFunc,
agentInfo: agentInfo,
}

// Send an invalid config update and confirm that Coordinator reports
Expand Down Expand Up @@ -582,6 +590,9 @@ func TestCoordinatorReportsComponentModelError(t *testing.T) {
defer cancel()
logger := logp.NewLogger("testing")

agentInfo, err := info.NewAgentInfo(t.Context(), false)
require.NoError(t, err)

// Channels have buffer length 1 so we don't have to run on multiple
// goroutines.
stateChan := make(chan State, 1)
Expand All @@ -607,6 +618,7 @@ func TestCoordinatorReportsComponentModelError(t *testing.T) {
ast: emptyAST(t),
componentPIDTicker: time.NewTicker(time.Second * 30),
secretMarkerFunc: testSecretMarkerFunc,
agentInfo: agentInfo,
}

// This configuration produces a valid AST but its EQL condition is
Expand Down
2 changes: 2 additions & 0 deletions internal/pkg/agent/application/periodic.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/elastic/elastic-agent/pkg/core/logger"
)

// periodic checks for local configuration changes
type periodic struct {
log *logger.Logger
period time.Duration
Expand Down Expand Up @@ -147,6 +148,7 @@ func newPeriodic(
}
}

// localConfigChange implements coordinator.ConfigChange for local file changes.
type localConfigChange struct {
cfg *config.Config
}
Expand Down
20 changes: 9 additions & 11 deletions internal/pkg/agent/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,19 +302,17 @@ func runElasticAgent(
errors.M(errors.MetaKeyPath, pathConfigFile))
}

// Set the initial log level (either default or from config file)
logger.SetLevel(logLvl)

// Ensure that the log level now matches what is configured in the agentInfo.
if agentInfo.LogLevel() != "" {
var lvl logp.Level
err = lvl.Unpack(agentInfo.LogLevel())
if err != nil {
l.Error(errors.New(err, "failed to parse agent information log level"))
} else {
logLvl = lvl
logger.SetLevel(lvl)
}
var lvl logp.Level
err = lvl.Unpack(agentInfo.LogLevel())
if err != nil {
l.Error(errors.New(err, "failed to parse agent information log level"))
} else {
// Set the initial log level (either default or from config file)
logger.SetLevel(logLvl)
logLvl = lvl
logger.SetLevel(lvl)
}

// initiate agent watcher
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/otel/manager/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type collectorExecution interface {
// - errCh: Process exit errors are sent to the errCh channel
// - statusCh: Collector's status updates are sent to statusCh channel.
// - forceFetchStatusCh: Channel that is used to trigger a forced status update.
startCollector(ctx context.Context, baseLogger *logger.Logger, logger *logger.Logger, cfg *confmap.Conf, errCh chan error, statusCh chan *status.AggregateStatus, forceFetchStatusCh chan struct{}) (collectorHandle, error)
startCollector(ctx context.Context, logLevel string, baseLogger *logger.Logger, logger *logger.Logger, cfg *confmap.Conf, errCh chan error, statusCh chan *status.AggregateStatus, forceFetchStatusCh chan struct{}) (collectorHandle, error)
}

type collectorHandle interface {
Expand Down
33 changes: 25 additions & 8 deletions internal/pkg/otel/manager/execution_subprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const (

// newSubprocessExecution creates a new execution which runs the otel collector in a subprocess. A metricsPort or
// healthCheckPort of 0 will result in a random port being used.
func newSubprocessExecution(logLevel logp.Level, collectorPath string, uuid string, metricsPort int, healthCheckPort int) (*subprocessExecution, error) {
func newSubprocessExecution(collectorPath string, uuid string, metricsPort int, healthCheckPort int) (*subprocessExecution, error) {
componentType, err := component.NewType(healthCheckExtensionName)
if err != nil {
return nil, fmt.Errorf("cannot create component type: %w", err)
Expand All @@ -52,21 +52,19 @@ func newSubprocessExecution(logLevel logp.Level, collectorPath string, uuid stri
collectorArgs: []string{
"otel",
fmt.Sprintf("--%s", OtelSetSupervisedFlagName),
fmt.Sprintf("--%s=%s", OtelSupervisedLoggingLevelFlagName, logLevel.String()),
fmt.Sprintf("--%s=%s", OtelSupervisedMonitoringURLFlagName, monitoring.EDOTMonitoringEndpoint()),
},
logLevel: logLevel,
healthCheckExtensionID: healthCheckExtensionID,
collectorMetricsPort: metricsPort,
collectorHealthCheckPort: healthCheckPort,
reportErrFn: reportErr,
}, nil
}

// subprocessExecution implements collectorExecution by running the collector in a subprocess.
type subprocessExecution struct {
collectorPath string
collectorArgs []string
logLevel logp.Level
healthCheckExtensionID string
collectorMetricsPort int
collectorHealthCheckPort int
Expand All @@ -75,7 +73,22 @@ type subprocessExecution struct {

// startCollector starts a supervised collector and monitors its health. Process exit errors are sent to the
// processErrCh channel. Other run errors, such as not able to connect to the health endpoint, are sent to the runErrCh channel.
func (r *subprocessExecution) startCollector(ctx context.Context, baseLogger *logger.Logger, logger *logger.Logger, cfg *confmap.Conf, processErrCh chan error, statusCh chan *status.AggregateStatus, forceFetchStatusCh chan struct{}) (collectorHandle, error) {
func (r *subprocessExecution) startCollector(
ctx context.Context,
logLevel string,
baseLogger *logger.Logger,
logger *logger.Logger,
cfg *confmap.Conf,
processErrCh chan error,
statusCh chan *status.AggregateStatus,
forceFetchStatusCh chan struct{},
) (collectorHandle, error) {
var lvl logp.Level
err := lvl.Unpack(logLevel)
if err != nil {
return nil, fmt.Errorf("failed to unpack the log level '%s': %w", logLevel, err)
}

if cfg == nil {
// configuration is required
return nil, errors.New("no configuration provided")
Expand Down Expand Up @@ -107,17 +120,21 @@ func (r *subprocessExecution) startCollector(ctx context.Context, baseLogger *lo
}

stdOutLast := newZapLast(baseLogger.Core())
stdOut := runtimeLogger.NewLogWriterWithDefaults(stdOutLast, zapcore.Level(r.logLevel))
stdOut := runtimeLogger.NewLogWriterWithDefaults(stdOutLast, zapcore.Level(lvl))
// info level for stdErr because by default collector writes to stderr
stdErrLast := newZapLast(baseLogger.Core())
stdErr := runtimeLogger.NewLogWriterWithDefaults(stdErrLast, zapcore.Level(r.logLevel))
stdErr := runtimeLogger.NewLogWriterWithDefaults(stdErrLast, zapcore.Level(lvl))

procCtx, procCtxCancel := context.WithCancel(ctx)
env := os.Environ()
// Set the environment variable for the collector metrics port. See comment at the constant definition for more information.
env = append(env, fmt.Sprintf("%s=%d", componentmonitoring.OtelCollectorMetricsPortEnvVarName, collectorMetricsPort))

// set collector args
collectorArgs := append(r.collectorArgs, fmt.Sprintf("--%s=%s", OtelSupervisedLoggingLevelFlagName, lvl))

processInfo, err := process.Start(r.collectorPath,
process.WithArgs(r.collectorArgs),
process.WithArgs(collectorArgs),
process.WithEnv(env),
process.WithCmdOptions(func(c *exec.Cmd) error {
c.Stdin = bytes.NewReader(confBytes)
Expand Down
Loading
Loading