Skip to content
Draft
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
79 changes: 69 additions & 10 deletions windows-agent/cmd/ubuntu-pro-agent/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.org/x/sys/windows/svc/eventlog"
)

// cmdName is the binary name for the agent.
Expand All @@ -43,10 +44,6 @@ type App struct {
ready chan struct{}
}

type daemonConfig struct {
Verbosity int
}

type options struct {
// publicDir is the directory where public data goes. Other components need access to it.
publicDir string
Expand Down Expand Up @@ -103,6 +100,8 @@ func New(o ...option) *App {

installVerbosityFlag(&a.rootCmd, a.viper)
installConfigFlag(&a.rootCmd)
installFileLogEnabledFlag(&a.rootCmd, a.viper)
installEventLogEnabledFlag(&a.rootCmd, a.viper)

// subcommands
a.installVersion()
Expand Down Expand Up @@ -251,18 +250,78 @@ func (a *App) setUpLogger(ctx context.Context) (func(), error) {
log.Warningf(ctx, "Could not archive previous log file: %v", err)
}

f, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE, 0600)
if err != nil {
return noop, fmt.Errorf("could not open log file: %v", err)
// Always write to stdout, which is useful for local development.
w := io.MultiWriter(os.Stdout)

var f *os.File
if a.config.FileLogEnabled {
f, err = os.OpenFile(logFile, os.O_APPEND|os.O_CREATE, 0600)
if err != nil {
return noop, fmt.Errorf("could not open log file: %v", err)
}
w = io.MultiWriter(w, f)
}

var eventLogger *eventlog.Log
if a.config.EventLogEnabled {
eventLogger, err = eventlog.Open(cmdName())
if err != nil {
return noop, err
}
logrus.AddHook(&eventLogHook{Writer: &eventLogWriter{eventLogger}})
}

// Write both to file and to Stdout. The latter is useful for local development.
w := io.MultiWriter(f, os.Stdout)
logrus.SetOutput(w)

fmt.Fprintf(f, "\n======= STARTUP =======\n")
log.Infof(ctx, "Version: %s", consts.Version)
log.Debug(ctx, "Debug mode is enabled")

return func() { _ = f.Close() }, nil
return func() {
if f != nil {
_ = f.Close()
}
if eventLogger != nil {
_ = eventLogger.Close()
}
}, nil
}

type eventLogWriter struct {
*eventlog.Log
}

func (writer *eventLogWriter) Write(p []byte) (n int, err error) {
err = writer.Info(0, string(p))
if err != nil {
return 0, err
}

return len(p), nil
}

type eventLogHook struct {
Writer *eventLogWriter
}

// Fire sends the log entry to the specified EventLog if the log level matches.
func (hook *eventLogHook) Fire(entry *logrus.Entry) error {
switch entry.Level {
case logrus.DebugLevel:
// EventLogWriter has no Debug function as of now, so use Info instead
return hook.Writer.Info(0, entry.Message)
case logrus.InfoLevel:
return hook.Writer.Info(0, entry.Message)
case logrus.WarnLevel:
return hook.Writer.Warning(0, entry.Message)
case logrus.ErrorLevel:
return hook.Writer.Error(0, entry.Message)
}

return fmt.Errorf("invalid log level %v", entry.Level)
}

// Levels returns the log levels that this hook should be registered with.
func (hook *eventLogHook) Levels() []logrus.Level {
return logrus.AllLevels
}
26 changes: 26 additions & 0 deletions windows-agent/cmd/ubuntu-pro-agent/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ import (
"github.com/ubuntu/decorate"
)

type daemonConfig struct {
Verbosity int
EventLogEnabled bool `mapstructure:"event-log-enabled"`
FileLogEnabled bool `mapstructure:"file-log-enabled"`
}

func initViperConfig(name string, cmd *cobra.Command, vip *viper.Viper) (err error) {
defer decorate.OnError(&err, "can't load configuration")

Expand Down Expand Up @@ -68,6 +74,26 @@ func installConfigFlag(cmd *cobra.Command) *string {
return cmd.PersistentFlags().StringP("config", "c", "", i18n.G("configuration file path"))
}

// installEventLogEnabledFlag adds the --event-log-enabled flag to allow for disabling event logging.
// Event logging is enabled by default.
func installEventLogEnabledFlag(cmd *cobra.Command, viper *viper.Viper) *bool {
r := cmd.PersistentFlags().BoolP("event-log-enabled", "e", true, i18n.G("whether to enable logging to the Windows event logger"))
if err := viper.BindPFlag("event-log-enabled", cmd.PersistentFlags().Lookup("event-log-enabled")); err != nil {
log.Warning(context.Background(), err)
}
return r
}

// installFileLogEnabledFlag adds the --file-log-enabled flag to allow for enabling file logging.
// File logging is disabled by default.
func installFileLogEnabledFlag(cmd *cobra.Command, viper *viper.Viper) *bool {
r := cmd.PersistentFlags().BoolP("file-log-enabled", "f", false, i18n.G("whether to enable logging to a log file"))
if err := viper.BindPFlag("file-log-enabled", cmd.PersistentFlags().Lookup("file-log-enabled")); err != nil {
log.Warning(context.Background(), err)
}
return r
}

// SetVerboseMode change ErrorFormat and logs between very, middly and non verbose.
func setVerboseMode(level int) {
var reportCaller bool
Expand Down