adding ability to write a log file with all output from collector. Executing commands will now log be logged (and when debug is enabled, their output's are also logged).

pull/38/head
Jason Kulatunga 4 years ago
parent 67d1c592a5
commit 297f0a51c5

@ -5,6 +5,7 @@ import (
"github.com/analogj/scrutiny/collector/pkg/collector" "github.com/analogj/scrutiny/collector/pkg/collector"
"github.com/analogj/scrutiny/webapp/backend/pkg/version" "github.com/analogj/scrutiny/webapp/backend/pkg/version"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"io"
"log" "log"
"os" "os"
"time" "time"
@ -85,6 +86,16 @@ OPTIONS:
logrus.SetLevel(logrus.InfoLevel) logrus.SetLevel(logrus.InfoLevel)
} }
if c.IsSet("log-file") {
logFile, err := os.OpenFile(c.String("log-file"), os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
logrus.Errorf("Failed to open log file %s for output: %s", c.String("log-file"), err)
return err
}
defer logFile.Close()
logrus.SetOutput(io.MultiWriter(os.Stderr, logFile))
}
metricCollector, err := collector.CreateMetricsCollector( metricCollector, err := collector.CreateMetricsCollector(
collectorLogger, collectorLogger,
c.String("api-endpoint"), c.String("api-endpoint"),
@ -105,6 +116,12 @@ OPTIONS:
EnvVars: []string{"SCRUTINY_API_ENDPOINT"}, EnvVars: []string{"SCRUTINY_API_ENDPOINT"},
}, },
&cli.StringFlag{
Name: "log-file",
Usage: "Path to file for logging. Leave empty to use STDOUT",
Value: "",
},
&cli.BoolFlag{ &cli.BoolFlag{
Name: "debug", Name: "debug",
Usage: "Enable debug logging", Usage: "Enable debug logging",

@ -5,6 +5,7 @@ import (
"github.com/analogj/scrutiny/collector/pkg/collector" "github.com/analogj/scrutiny/collector/pkg/collector"
"github.com/analogj/scrutiny/webapp/backend/pkg/version" "github.com/analogj/scrutiny/webapp/backend/pkg/version"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"io"
"log" "log"
"os" "os"
"time" "time"
@ -85,6 +86,16 @@ OPTIONS:
logrus.SetLevel(logrus.InfoLevel) logrus.SetLevel(logrus.InfoLevel)
} }
if c.IsSet("log-file") {
logFile, err := os.OpenFile(c.String("log-file"), os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
logrus.Errorf("Failed to open log file %s for output: %s", c.String("log-file"), err)
return err
}
defer logFile.Close()
logrus.SetOutput(io.MultiWriter(os.Stderr, logFile))
}
stCollector, err := collector.CreateSelfTestCollector( stCollector, err := collector.CreateSelfTestCollector(
collectorLogger, collectorLogger,
c.String("api-endpoint"), c.String("api-endpoint"),
@ -105,6 +116,12 @@ OPTIONS:
EnvVars: []string{"SCRUTINY_API_ENDPOINT"}, EnvVars: []string{"SCRUTINY_API_ENDPOINT"},
}, },
&cli.StringFlag{
Name: "log-file",
Usage: "Path to file for logging. Leave empty to use STDOUT",
Value: "",
},
&cli.BoolFlag{ &cli.BoolFlag{
Name: "debug", Name: "debug",
Usage: "Enable debug logging", Usage: "Enable debug logging",

@ -109,7 +109,7 @@ func (mc *MetricsCollector) Collect(wg *sync.WaitGroup, deviceWWN string, device
} }
args = append(args, fmt.Sprintf("%s%s", detect.DevicePrefix(), deviceName)) args = append(args, fmt.Sprintf("%s%s", detect.DevicePrefix(), deviceName))
result, err := common.ExecCmd("smartctl", args, "", os.Environ()) result, err := common.ExecCmd(mc.logger, "smartctl", args, "", os.Environ())
resultBytes := []byte(result) resultBytes := []byte(result)
if err != nil { if err != nil {
if exitError, ok := err.(*exec.ExitError); ok { if exitError, ok := err.(*exec.ExitError); ok {

@ -3,17 +3,19 @@ package common
import ( import (
"bytes" "bytes"
"errors" "errors"
"github.com/sirupsen/logrus"
"io" "io"
"os"
"os/exec" "os/exec"
"path" "path"
"strings"
) )
func ExecCmd(cmdName string, cmdArgs []string, workingDir string, environ []string) (string, error) { func ExecCmd(logger *logrus.Entry, cmdName string, cmdArgs []string, workingDir string, environ []string) (string, error) {
logger.Infof("Executing command: %s %s", cmdName, strings.Join(cmdArgs, " "))
cmd := exec.Command(cmdName, cmdArgs...) cmd := exec.Command(cmdName, cmdArgs...)
var stdBuffer bytes.Buffer var stdBuffer bytes.Buffer
mw := io.MultiWriter(os.Stdout, &stdBuffer) mw := io.MultiWriter(logger.Logger.Out, &stdBuffer)
cmd.Stdout = mw cmd.Stdout = mw
cmd.Stderr = mw cmd.Stderr = mw

@ -2,6 +2,7 @@ package common_test
import ( import (
"github.com/analogj/scrutiny/collector/pkg/common" "github.com/analogj/scrutiny/collector/pkg/common"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"os/exec" "os/exec"
"testing" "testing"
@ -13,7 +14,7 @@ func TestExecCmd(t *testing.T) {
//setup //setup
//test //test
result, err := common.ExecCmd("echo", []string{"hello world"}, "", nil) result, err := common.ExecCmd(logrus.WithField("exec", "test"), "echo", []string{"hello world"}, "", nil)
//assert //assert
require.NoError(t, err) require.NoError(t, err)
@ -26,7 +27,7 @@ func TestExecCmd_Date(t *testing.T) {
//setup //setup
//test //test
_, err := common.ExecCmd("date", []string{}, "", nil) _, err := common.ExecCmd(logrus.WithField("exec", "test"), "date", []string{}, "", nil)
//assert //assert
require.NoError(t, err) require.NoError(t, err)
@ -56,7 +57,7 @@ func TestExecCmd_InvalidCommand(t *testing.T) {
//setup //setup
//test //test
_, err := common.ExecCmd("invalid_binary", []string{}, "", nil) _, err := common.ExecCmd(logrus.WithField("exec", "test"), "invalid_binary", []string{}, "", nil)
//assert //assert
_, castOk := err.(*exec.ExitError) _, castOk := err.(*exec.ExitError)

@ -26,7 +26,7 @@ type Detect struct {
// models.Device returned from this function only contain the minimum data for smartctl to execute: device type and device name (device file). // models.Device returned from this function only contain the minimum data for smartctl to execute: device type and device name (device file).
func (d *Detect) smartctlScan() ([]models.Device, error) { func (d *Detect) smartctlScan() ([]models.Device, error) {
//we use smartctl to detect all the drives available. //we use smartctl to detect all the drives available.
detectedDeviceConnJson, err := common.ExecCmd("smartctl", []string{"--scan", "-j"}, "", os.Environ()) detectedDeviceConnJson, err := common.ExecCmd(d.Logger, "smartctl", []string{"--scan", "-j"}, "", os.Environ())
if err != nil { if err != nil {
d.Logger.Errorf("Error scanning for devices: %v", err) d.Logger.Errorf("Error scanning for devices: %v", err)
return nil, err return nil, err
@ -64,7 +64,7 @@ func (d *Detect) smartCtlInfo(device *models.Device) error {
} }
args = append(args, fmt.Sprintf("%s%s", DevicePrefix(), device.DeviceName)) args = append(args, fmt.Sprintf("%s%s", DevicePrefix(), device.DeviceName))
availableDeviceInfoJson, err := common.ExecCmd("smartctl", args, "", os.Environ()) availableDeviceInfoJson, err := common.ExecCmd(d.Logger, "smartctl", args, "", os.Environ())
if err != nil { if err != nil {
d.Logger.Errorf("Could not retrieve device information for %s: %v", device.DeviceName, err) d.Logger.Errorf("Could not retrieve device information for %s: %v", device.DeviceName, err)
return err return err
@ -101,6 +101,7 @@ func (d *Detect) smartCtlInfo(device *models.Device) error {
Id: availableDeviceInfo.Wwn.ID, Id: availableDeviceInfo.Wwn.ID,
} }
device.WWN = wwn.ToString() device.WWN = wwn.ToString()
d.Logger.Debugf("NAA: %d OUI: %d Id: %d => WWN: %s", wwn.Naa, wwn.Oui, wwn.Id, device.WWN)
} else { } else {
d.Logger.Info("Using WWN Fallback") d.Logger.Info("Using WWN Fallback")
d.wwnFallback(device) d.wwnFallback(device)

@ -93,6 +93,7 @@ func (d *Detect) wwnFallback(detectedDevice *models.Device) {
if err == nil { if err == nil {
for _, disk := range block.Disks { for _, disk := range block.Disks {
if disk.Name == detectedDevice.DeviceName { if disk.Name == detectedDevice.DeviceName {
d.Logger.Debugf("Found matching block device. WWN: %s", disk.WWN)
detectedDevice.WWN = disk.WWN detectedDevice.WWN = disk.WWN
break break
} }
@ -101,6 +102,7 @@ func (d *Detect) wwnFallback(detectedDevice *models.Device) {
//no WWN found, or could not open Block devices. Either way, fallback to serial number //no WWN found, or could not open Block devices. Either way, fallback to serial number
if len(detectedDevice.WWN) == 0 { if len(detectedDevice.WWN) == 0 {
d.Logger.Debugf("WWN is empty, falling back to serial number: %s", detectedDevice.SerialNumber)
detectedDevice.WWN = detectedDevice.SerialNumber detectedDevice.WWN = detectedDevice.SerialNumber
} }
} }

@ -30,6 +30,7 @@ func (d *Detect) wwnFallback(detectedDevice *models.Device) {
if err == nil { if err == nil {
for _, disk := range block.Disks { for _, disk := range block.Disks {
if disk.Name == detectedDevice.DeviceName { if disk.Name == detectedDevice.DeviceName {
d.Logger.Debugf("Found matching block device. WWN: %s", disk.WWN)
detectedDevice.WWN = disk.WWN detectedDevice.WWN = disk.WWN
break break
} }
@ -38,6 +39,7 @@ func (d *Detect) wwnFallback(detectedDevice *models.Device) {
//no WWN found, or could not open Block devices. Either way, fallback to serial number //no WWN found, or could not open Block devices. Either way, fallback to serial number
if len(detectedDevice.WWN) == 0 { if len(detectedDevice.WWN) == 0 {
d.Logger.Debugf("WWN is empty, falling back to serial number: %s", detectedDevice.SerialNumber)
detectedDevice.WWN = detectedDevice.SerialNumber detectedDevice.WWN = detectedDevice.SerialNumber
} }
} }

Loading…
Cancel
Save