Skip to content

Commit

Permalink
Logging & output improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
eddie-knight committed Aug 21, 2023
1 parent 71faac9 commit 92c9841
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 110 deletions.
17 changes: 9 additions & 8 deletions command/command.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package command

import (
"fmt"
"log"
"os"
"path/filepath"
"strings"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/privateerproj/privateer-sdk/logging"
)

// SetBase sets the base flags for all commands
Expand All @@ -30,19 +29,21 @@ func InitializeConfig() {

viper.SetDefault("loglevel", "Error")
viper.SetConfigFile(viper.GetString("config"))
loglevel := setLogLevelFromFlag()
setLogLevelFromFlag()
viper.AutomaticEnv()
logger := logging.GetLogger("execution", loglevel, false)

logger.Info(fmt.Sprintf("Reading config file: %s (loglevel: %s)", viper.GetString("config"), loglevel))
if err := viper.ReadInConfig(); err != nil {
logger.Debug(err.Error())
log.Print(err.Error())
}

// TODO: Logging at this location has unexpected behavior related to the WriteDirectory and loglevel
// raidengine.GetLogger("overview", false).Debug("Lauching Privateer with loglevel '%s' and config file: %s", loglevel, viper.GetString("config"))
}

// setLogLevelFromFlag sets the log level based on the verbose and silent flags
func setLogLevelFromFlag() string {
if viper.GetBool("verbose") {
// If verbose is set, and loglevel is not trace (highest level), set loglevel to debug
if viper.GetBool("verbose") && !strings.EqualFold(viper.GetString("loglevel"), "trace") {
viper.Set("loglevel", "debug")
} else if viper.GetBool("silent") {
viper.Set("loglevel", "off")
Expand Down
49 changes: 0 additions & 49 deletions logging/logging.go

This file was deleted.

19 changes: 2 additions & 17 deletions plugin/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

hclog "github.com/hashicorp/go-hclog"
hcplugin "github.com/hashicorp/go-plugin"
"github.com/privateerproj/privateer-sdk/logging"
)

// RaidPluginName TODO: why did we put this here? what is this doing? Review and justify this.
Expand All @@ -24,26 +23,11 @@ type ServeOpts struct {

// Logger is the logger that go-plugin will use.
Logger hclog.Logger

// Set NoLogOutputOverride to not override the log output with an hclog
// adapter. This should only be used when running the plugin in
// acceptance tests.
NoLogOutputOverride bool
}

// Serve serves a plugin. This function never returns and should be the final
// function called in the main function of the plugin.
func Serve(opts *ServeOpts) {
if !opts.NoLogOutputOverride {
// In order to allow go-plugin to correctly pass log-levels through,
// we need to use an hclog.Logger with JSON output. We can
// inject this into the std `log` package here, so existing providers will
// make use of it automatically.
logger := logging.GetLogger("", "Error", true)
log.SetOutput(logger.StandardWriter(&hclog.StandardLoggerOptions{InferLevels: true}))
}

// Plugin implementation
func Serve(raidName string, opts *ServeOpts) {
// Guard Clause: Ensure plugin is not nil
if opts.Plugin == nil {
log.Panic("Invalid (nil) plugin implementation provided")
Expand All @@ -59,6 +43,7 @@ func Serve(opts *ServeOpts) {
Plugins: hcpluginMap,
Logger: opts.Logger,
})
log.Printf("Successfully completed raid: %s", raidName)
}

// GetHandshakeConfig provides handshake config details. It is used by core and service packs.
Expand Down
134 changes: 134 additions & 0 deletions raidengine/output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package raidengine

import (
"encoding/json"
"errors"
"io"
"log"
"os"
"path"

hclog "github.com/hashicorp/go-hclog"
"github.com/spf13/viper"
yaml "gopkg.in/yaml.v3"
)

// GetLogger returns an hc logger with the provided name.
// It will creates or update the logger to use the provided level and format.
// If the logger already exists, it will return the existing logger.
// For level options, reference:
// https://github.com/hashicorp/go-hclog/blob/master/logger.go#L19
func GetLogger(name string, jsonFormat bool) hclog.Logger {
// Initialize file writer for MultiWriter
var filepath string
if name == "overview" {
// if this is not a raid, do not nest within a directory
filepath = path.Join(viper.GetString("WriteDirectory"), name+".log")
} else {
// otherwise, nest within a directory with the same name as the raid
filepath = path.Join(viper.GetString("WriteDirectory"), name, name+".log")
}

// Create log file and directory if it doesn't exist
if _, err := os.Stat(filepath); os.IsNotExist(err) {
// mkdir all directories from filepath
os.MkdirAll(path.Dir(filepath), os.ModePerm)
os.Create(filepath)
}

logFile, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640)

if err != nil {
log.Panic(err) // TODO handle this error better
}
multi := io.MultiWriter(logFile, os.Stdout)

logger := hclog.New(&hclog.LoggerOptions{
Level: hclog.LevelFromString(viper.GetString("loglevel")),
JSONFormat: jsonFormat,
Output: multi,
})
log.SetOutput(logger.StandardWriter(&hclog.StandardLoggerOptions{InferLevels: false, InferLevelsWithTimestamp: false}))
// log.SetFlags(0)
return logger
}

// AddStrikeResult adds a StrikeResult to the RaidResults
func (r *RaidResults) AddStrikeResult(name string, result StrikeResult) {
if r.StrikeResults == nil {
r.StrikeResults = make(map[string]StrikeResult)
}
r.StrikeResults[name] = result
}

// WriteStrikeResultsJSON unmarhals the RaidResults into a JSON file in the user's WriteDirectory
func (r *RaidResults) WriteStrikeResultsJSON() error {
// Log an error if RaidName was not provided
if r.RaidName == "" {
return errors.New("RaidName was not provided before attempting to write results")
}
filepath := path.Join(viper.GetString("WriteDirectory"), r.RaidName, "results.json")

// Create log file and directory if it doesn't exist
if _, err := os.Stat(filepath); os.IsNotExist(err) {
os.MkdirAll(viper.GetString("WriteDirectory"), os.ModePerm)
os.Create(filepath)
}

// Write results to file
file, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640)
if err != nil {
return err
}
defer file.Close()

// Marshal results to JSON
json, err := json.Marshal(r)
if err != nil {
return err
}

// Write JSON to file
_, err = file.Write(json)
if err != nil {
return err
}

return nil
}

// WriteStrikeResultsYAML unmarhals the RaidResults into a YAML file in the user's WriteDirectory
func (r *RaidResults) WriteStrikeResultsYAML() error {
// Log an error if RaidName was not provided
if r.RaidName == "" {
return errors.New("RaidName was not provided before attempting to write results")
}
filepath := path.Join(viper.GetString("WriteDirectory"), r.RaidName, "results.yaml")

// Create log file and directory if it doesn't exist
if _, err := os.Stat(filepath); os.IsNotExist(err) {
os.MkdirAll(viper.GetString("WriteDirectory"), os.ModePerm)
os.Create(filepath)
}

// Write results to file
file, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640)
if err != nil {
return err
}
defer file.Close()

// Marshal results to YAML
yaml, err := yaml.Marshal(r)
if err != nil {
return err
}

// Write YAML to file
_, err = file.Write(yaml)
if err != nil {
return err
}

return nil
}
Loading

0 comments on commit 92c9841

Please sign in to comment.