Skip to content

Commit

Permalink
add an in-memory logger and use it on install and uninstall (#4485)
Browse files Browse the repository at this point in the history
  • Loading branch information
AndersonQ authored Mar 27, 2024
1 parent ce229d2 commit 4cf1253
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 36 deletions.
19 changes: 2 additions & 17 deletions internal/pkg/agent/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,28 +193,13 @@ func installCmd(streams *cli.IOStreams, cmd *cobra.Command) error {

progBar := install.CreateAndStartNewSpinner(streams.Out, "Installing Elastic Agent...")

logCfg := logp.DefaultConfig(logp.DefaultEnvironment)
logCfg.Level = logp.DebugLevel
// Using in memory logger, so we don't write logs to the
// directory we are trying to delete
logp.ToObserverOutput()(&logCfg)

err = logp.Configure(logCfg)
if err != nil {
return fmt.Errorf("error creating logging config: %w", err)
}

log := logger.NewWithoutConfig("")

log, logBuff := logger.NewInMemory("install", logp.ConsoleEncoderConfig())
defer func() {
if err == nil {
return
}
oLogs := logp.ObserverLogs().TakeAll()
fmt.Fprintf(os.Stderr, "Error uninstalling. Printing logs\n")
for _, oLog := range oLogs {
fmt.Fprintf(os.Stderr, "%v\n", oLog.Entry)
}
fmt.Fprint(os.Stderr, logBuff.String())
}()

var ownership utils.FileOwner
Expand Down
20 changes: 2 additions & 18 deletions internal/pkg/agent/cmd/uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/spf13/cobra"

"github.com/elastic/elastic-agent-libs/logp"

"github.com/elastic/elastic-agent/internal/pkg/agent/application/paths"
"github.com/elastic/elastic-agent/internal/pkg/agent/install"
"github.com/elastic/elastic-agent/internal/pkg/cli"
Expand Down Expand Up @@ -86,28 +85,13 @@ func uninstallCmd(streams *cli.IOStreams, cmd *cobra.Command) error {

progBar := install.CreateAndStartNewSpinner(streams.Out, "Uninstalling Elastic Agent...")

logCfg := logp.DefaultConfig(logp.DefaultEnvironment)
logCfg.Level = logp.DebugLevel
// Using in memory logger, so we don't write logs to the
// directory we are trying to delete
logp.ToObserverOutput()(&logCfg)

err = logp.Configure(logCfg)
if err != nil {
return fmt.Errorf("error creating logging config: %w", err)
}

log := logger.NewWithoutConfig("")

log, logBuff := logger.NewInMemory("uninstall", logp.ConsoleEncoderConfig())
defer func() {
if err == nil {
return
}
oLogs := logp.ObserverLogs().TakeAll()
fmt.Fprintf(os.Stderr, "Error uninstalling. Printing logs\n")
for _, oLog := range oLogs {
fmt.Fprintf(os.Stderr, "%v\n", oLog.Entry)
}
fmt.Fprint(os.Stderr, logBuff.String())
}()

err = install.Uninstall(paths.ConfigFile(), paths.Top(), uninstallToken, log, progBar)
Expand Down
28 changes: 27 additions & 1 deletion pkg/core/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package logger

import (
"bytes"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -72,6 +73,31 @@ func NewWithoutConfig(name string) *Logger {
return logp.NewLogger(name)
}

// NewInMemory returns a new in-memory logger along with the buffer to which i
// logs.
// encCfg configures the log format, use logp.ConsoleEncoderConfig for console
// format, logp.JSONEncoderConfig for JSON or any other valid zapcore.EncoderConfig.
func NewInMemory(selector string, encCfg zapcore.EncoderConfig) (*Logger, *bytes.Buffer) {
buff := bytes.Buffer{}

encoderConfig := ecszap.ECSCompatibleEncoderConfig(encCfg)
encoderConfig.EncodeTime = UtcTimestampEncode
encoder := zapcore.NewConsoleEncoder(encoderConfig)

core := zapcore.NewCore(
encoder,
zapcore.AddSync(&buff),
zap.NewAtomicLevelAt(zap.DebugLevel))
ecszap.ECSCompatibleEncoderConfig(logp.ConsoleEncoderConfig())

logger := logp.NewLogger(
selector,
zap.WrapCore(func(in zapcore.Core) zapcore.Core {
return core
}))
return logger, &buff
}

// AddCallerSkip returns new logger with incremented stack frames to skip.
// This is needed in order to correctly report the log file lines when the logging statement
// is wrapped in some convenience wrapping function for example.
Expand Down Expand Up @@ -147,7 +173,7 @@ func DefaultLoggingConfig() *Config {
return &cfg
}

// makeInternalFileOutput creates a zapcore.Core logger that cannot be changed with configuration.
// MakeInternalFileOutput creates a zapcore.Core logger that cannot be changed with configuration.
//
// This is the logger that the spawned filebeat expects to read the log file from and ship to ES.
func MakeInternalFileOutput(cfg *Config) (zapcore.Core, error) {
Expand Down
30 changes: 30 additions & 0 deletions pkg/core/logger/logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
package logger

import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zapcore"

Expand Down Expand Up @@ -56,3 +58,31 @@ func Test_SetLevel(t *testing.T) {
require.Equal(t, tc.ErrEnabled, internalLevelEnabler.Enabled(zapcore.ErrorLevel))
}
}

func TestNewInMemory(t *testing.T) {
log, buff := NewInMemory("in_memory", logp.ConsoleEncoderConfig())

log.Debugw("a debug message", "debug_key", "debug_val")
log.Infow("a info message", "info_key", "info_val")
log.Warnw("a warn message", "warn_key", "warn_val")
log.Errorw("an error message", "error_key", "error_val")

logs := strings.Split(strings.TrimSpace(buff.String()), "\n")
assert.Len(t, logs, 4, "expected 4 log entries")

assert.Contains(t, logs[0], "a debug message")
assert.Contains(t, logs[0], "debug_key")
assert.Contains(t, logs[0], "debug_val")

assert.Contains(t, logs[1], "a info message")
assert.Contains(t, logs[1], "info_key")
assert.Contains(t, logs[1], "info_val")

assert.Contains(t, logs[2], "a warn message")
assert.Contains(t, logs[2], "warn_key")
assert.Contains(t, logs[2], "warn_val")

assert.Contains(t, logs[3], "an error message")
assert.Contains(t, logs[3], "error_key")
assert.Contains(t, logs[3], "error_val")
}

0 comments on commit 4cf1253

Please sign in to comment.