Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Integrate gosteno logging

Change-Id: Idd9b19362566cbe42349f0e61f92a4f80504fada
  • Loading branch information...
commit 53e6d8b9e4021000a06a7626bdef5d4121cbf53a 1 parent 6708840
@dougm dougm authored
View
7 api.go
@@ -4,9 +4,8 @@ package gonit
import (
"errors"
- "sort"
"github.com/cloudfoundry/gosigar"
- "log"
+ "sort"
)
// until stubs are implemented
@@ -288,7 +287,7 @@ func (a *API) About(unused interface{}, about *About) error {
// reload server configuration
func (a *API) Reload(unused interface{}, r *ActionResult) error {
- log.Printf("Starting config reload.")
+ Log.Info("Starting config reload")
control := a.Control
path := control.ConfigManager.path
newConfigManager := ConfigManager{}
@@ -302,7 +301,7 @@ func (a *API) Reload(unused interface{}, r *ActionResult) error {
control); err != nil {
return err
}
- log.Printf("Finished config reload.")
+ Log.Info("Finished config reload")
return nil
}
View
11 configmanager.go
@@ -6,7 +6,6 @@ import (
"fmt"
"github.com/xushiwei/goyaml"
"io/ioutil"
- "log"
"os"
"path/filepath"
"strings"
@@ -31,6 +30,7 @@ type Settings struct {
PollInterval int
Daemon *Process
PersistFile string
+ Logging *LoggerConfig
}
type ProcessGroup struct {
@@ -126,7 +126,7 @@ func (c *ConfigManager) parseConfigFile(path string) (*ProcessGroup, error) {
if err := goyaml.Unmarshal(b, processGroup); err != nil {
return nil, err
}
- log.Printf("Loaded config file '%+v'\n", path)
+ Log.Infof("Loaded config file '%+v'", path)
return processGroup, nil
}
@@ -140,7 +140,7 @@ func (c *ConfigManager) parseSettingsFile(path string) (*Settings, error) {
if err := goyaml.Unmarshal(b, settings); err != nil {
return nil, err
}
- log.Printf("Loaded settings file: '%+v'\n", path)
+ Log.Infof("Loaded settings file: '%+v'", path)
return settings, nil
}
@@ -179,6 +179,9 @@ func (c *ConfigManager) ApplyDefaultSettings() {
if settings.AlertTransport == "" {
settings.AlertTransport = DEFAULT_ALERT_TRANSPORT
}
+ if settings.Logging == nil {
+ settings.Logging = &LoggerConfig{}
+ }
if settings.Daemon == nil {
settings.Daemon = &Process{}
}
@@ -261,7 +264,7 @@ func (c *ConfigManager) LoadConfig(path string) error {
}
c.fillInNames()
if (*c.Settings == Settings{}) {
- log.Printf("No settings found, using defaults.")
+ Log.Info("No settings found, using defaults")
}
c.ApplyDefaultSettings()
c.applyDefaultConfigOpts()
View
2  configmanager_test.go
@@ -31,6 +31,8 @@ func assertFileParsed(t *testing.T, configManager *ConfigManager) {
assert.Equal(t, 0, configManager.Settings.PollInterval)
assert.NotEqual(t, nil, configManager.Settings.Daemon)
assert.Equal(t, "lolnit", configManager.Settings.Daemon.Name)
+ assert.NotEqual(t, nil, configManager.Settings.Logging)
+ assert.Equal(t, "debug", configManager.Settings.Logging.Level)
}
func TestGetPid(t *testing.T) {
View
26 control.go
@@ -6,7 +6,6 @@ import (
"fmt"
"github.com/xushiwei/goyaml"
"io/ioutil"
- "log"
"os"
"sync"
"time"
@@ -164,14 +163,14 @@ func (c *Control) DoAction(name string, action int) error {
process, err := c.Config().FindProcess(name)
if err != nil {
- log.Print(err)
+ Log.Error(err.Error())
return err
}
switch action {
case ACTION_START:
if process.IsRunning() {
- log.Printf("Process %q already running", name)
+ Log.Debugf("Process %q already running", name)
c.monitorSet(process)
return nil
}
@@ -200,13 +199,12 @@ func (c *Control) DoAction(name string, action int) error {
c.doUnmonitor(process)
default:
- err = fmt.Errorf("process %q -- invalid action: %d",
+ Log.Errorf("process %q -- invalid action: %d",
process.Name, action)
- log.Print(err)
return err
}
if err := c.PersistStates(c.States); err != nil {
- log.Printf("Error persisting state: '%v'.\n", err.Error())
+ Log.Errorf("Error persisting state: '%v'", err.Error())
}
return nil
}
@@ -320,7 +318,7 @@ func (c *Control) monitorSet(process *Process) {
if state.Monitor == MONITOR_NOT {
state.Monitor = MONITOR_INIT
c.EventMonitor.StartMonitoringProcess(process)
- log.Printf("%q monitoring enabled", process.Name)
+ Log.Infof("%q monitoring enabled", process.Name)
}
}
@@ -330,7 +328,7 @@ func (c *Control) monitorUnset(process *Process) {
defer state.MonitorLock.Unlock()
if state.Monitor != MONITOR_NOT {
state.Monitor = MONITOR_NOT
- log.Printf("%q monitoring disabled", process.Name)
+ Log.Infof("%q monitoring disabled", process.Name)
}
}
@@ -375,16 +373,16 @@ func (p *Process) waitState(expect int) int {
// XXX TODO emit events when process state changes
if isRunning {
if expect == processStarted {
- log.Printf("process %q started", p.Name)
+ Log.Infof("process %q started", p.Name)
} else {
- log.Printf("process %q failed to stop", p.Name)
+ Log.Errorf("process %q failed to stop", p.Name)
}
return processStarted
} else {
if expect == processStarted {
- log.Printf("process %q failed to start", p.Name)
+ Log.Errorf("process %q failed to start", p.Name)
} else {
- log.Printf("process %q stopped", p.Name)
+ Log.Infof("process %q stopped", p.Name)
}
return processStopped
}
@@ -397,7 +395,7 @@ func (c *Control) LoadPersistState() error {
persistFile := c.ConfigManager.Settings.PersistFile
_, err := os.Stat(persistFile)
if err != nil {
- log.Printf("No persisted state found at '%v'.", persistFile)
+ Log.Debugf("No persisted state found at '%v'", persistFile)
return nil
}
persistData, err := ioutil.ReadFile(persistFile)
@@ -429,6 +427,6 @@ func (c *Control) PersistStates(states map[string]*ProcessState) error {
if err = ioutil.WriteFile(persistFile, []byte(yaml), 0644); err != nil {
return err
}
- log.Printf("Persisted state to '%v'.", persistFile)
+ Log.Debugf("Persisted state to '%v'", persistFile)
return nil
}
View
19 eventmonitor.go
@@ -5,7 +5,6 @@ package gonit
import (
"encoding/json"
"fmt"
- "log"
"math"
"net"
"strings"
@@ -151,7 +150,7 @@ func (e *EventMonitor) setup(configManager *ConfigManager,
func (e *EventMonitor) printTriggeredMessage(event *ParsedEvent,
resourceVal uint64) {
- log.Printf("'%v' triggered '%v' for '%v' (at '%v'). Executing '%v'.\n",
+ Log.Infof("'%v' triggered '%v' for '%v' (at '%v'). Executing '%v'",
event.processName, event.ruleString, event.duration, resourceVal,
event.action)
}
@@ -198,15 +197,15 @@ func (e *EventMonitor) Start(configManager *ConfigManager,
if err := e.setup(configManager, control); err != nil {
return err
}
- log.Println("Starting new eventmonitor loop.")
+ Log.Info("Starting new eventmonitor loop.")
go func() {
timeToWait := 1 * time.Second
ticker := time.NewTicker(timeToWait)
- log.Println("Started new eventmonitor loop.")
+ Log.Info("Started new eventmonitor loop.")
for {
select {
case <-e.quitChan:
- log.Println("Quit old eventmonitor loop.")
+ Log.Info("Quit old eventmonitor loop.")
ticker.Stop()
return
case <-ticker.C:
@@ -218,8 +217,8 @@ func (e *EventMonitor) Start(configManager *ConfigManager,
// file.
pid, err := process.Pid()
if err != nil {
- log.Printf("Could not get pid file for process '%v'. Error: "+
- "%+v\n", process.Name, err)
+ Log.Debugf("Could not get pid file for process '%v'. Error: "+
+ "%+v", process.Name, err)
}
e.checkRules(process, pid)
}
@@ -232,7 +231,7 @@ func (e *EventMonitor) Start(configManager *ConfigManager,
}
func (e *EventMonitor) Stop() {
- log.Println("Quitting old eventmonitor loop.")
+ Log.Info("Quitting old eventmonitor loop.")
e.quitChan <- true
close(e.quitChan)
e.resourceManager.CleanData()
@@ -251,14 +250,14 @@ func (e *EventMonitor) checkRules(process *Process, pid int) {
var err error
resourceVal, err = e.resourceManager.GetResource(event, pid)
if err != nil {
- log.Print(err)
+ Log.Error(err.Error())
continue
}
ruleTriggered := checkRule(event, resourceVal)
if ruleTriggered {
// TODO right now this can block the monitoring loop.
if err := e.triggerAction(process, event, resourceVal); err != nil {
- log.Print(err)
+ Log.Error(err.Error())
}
}
}
View
11 gonit/main.go
@@ -21,6 +21,7 @@ var (
config string
pidfile string
rpcUrl string
+ logLevel string
poll int
group bool
foreground bool
@@ -55,6 +56,10 @@ func main() {
settings = configManager.Settings
applySettings()
+ if err := settings.Logging.Init(); err != nil {
+ log.Fatal(err)
+ }
+
api = gonit.NewAPI(configManager)
args := flag.Args()
if len(args) == 0 {
@@ -84,6 +89,9 @@ func applySettings() {
if poll != 0 {
settings.PollInterval = poll
}
+ if logLevel != "" {
+ settings.Logging.Level = logLevel
+ }
}
func parseFlags() {
@@ -94,6 +102,7 @@ func parseFlags() {
flag.StringVar(&pidfile, "p", "", "Pid file path")
flag.StringVar(&rpcUrl, "s", "", "RPC server URL")
flag.IntVar(&poll, "d", 0, "Run as a daemon with duration")
+ flag.StringVar(&logLevel, "l", "", "Log level")
const named = "the named process or group"
const all = "all processes"
@@ -203,6 +212,8 @@ func shutdown() {
rpcServer.Shutdown()
}
+ settings.Logging.Close()
+
os.Exit(0)
}
View
73 log.go
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 VMware, Inc.
+
+package gonit
+
+import (
+ "github.com/cloudfoundry/gosteno"
+ "os"
+)
+
+var Log steno.Logger
+
+type LoggerConfig struct {
+ Level string
+ FileName string
+ Codec string
+ file *os.File
+}
+
+func init() {
+ // default configuration
+ config := &LoggerConfig{}
+ err := config.Init()
+ if err != nil {
+ panic(err)
+ }
+}
+
+func (lc *LoggerConfig) Init() error {
+ var file *os.File
+ var level *steno.LogLevel
+ var err error
+
+ if lc.Level != "" {
+ level, err = steno.GetLogLevel(lc.Level)
+ if err != nil {
+ return err
+ }
+ }
+
+ if lc.FileName == "" {
+ file = os.Stdout
+ } else {
+ flags := os.O_APPEND | os.O_CREATE | os.O_WRONLY
+ lc.file, err = os.OpenFile(lc.FileName, flags, 0666)
+ if err != nil {
+ return err
+ }
+ file = lc.file
+ }
+
+ out := steno.NewIOSink(file)
+
+ if lc.Codec != "json" {
+ out.SetCodec(steno.NewJsonPrettifier(steno.EXCLUDE_DATA))
+ }
+
+ steno.Init(&steno.Config{
+ EnableLOC: true,
+ Sinks: []steno.Sink{out},
+ Level: level,
+ })
+
+ Log = steno.NewLogger("gonit")
+
+ return nil
+}
+
+func (lc *LoggerConfig) Close() error {
+ if lc.file != nil {
+ return lc.file.Close()
+ }
+ return nil
+}
View
81 log_test.go
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 VMware, Inc.
+
+package gonit
+
+import (
+ "github.com/bmizerany/assert"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+func reInitLogger() {
+ (&LoggerConfig{}).Init() // reset to defaults
+}
+
+func TestLogInit(t *testing.T) {
+ defer reInitLogger()
+
+ config := &LoggerConfig{
+ Level: "debug",
+ }
+
+ err := config.Init()
+ assert.Equal(t, nil, err)
+ var empty *os.File
+ assert.Equal(t, empty, config.file)
+ err = config.Close()
+ assert.Equal(t, nil, err)
+}
+
+func TestInvalidLogLevel(t *testing.T) {
+ defer reInitLogger()
+
+ config := &LoggerConfig{
+ Level: "enolevel",
+ }
+
+ err := config.Init()
+ assert.NotEqual(t, nil, err)
+}
+
+func TestLogFile(t *testing.T) {
+ defer reInitLogger()
+
+ file, err := ioutil.TempFile("", "gonit_log")
+ assert.Equal(t, nil, err)
+ defer os.Remove(file.Name())
+
+ config := &LoggerConfig{
+ FileName: file.Name(),
+ Level: "info",
+ }
+
+ err = config.Init()
+ assert.Equal(t, nil, err)
+
+ fi, err := os.Stat(config.FileName)
+ assert.Equal(t, nil, err)
+ assert.Equal(t, fi.Size(), int64(0))
+
+ // info message should be written to the log file
+ Log.Info("testing")
+ fi, err = os.Stat(config.FileName)
+ assert.Equal(t, nil, err)
+ assert.NotEqual(t, fi.Size(), int64(0))
+
+ // info message should not
+ Log.Debug("another test")
+ fi2, err := os.Stat(config.FileName)
+ assert.Equal(t, nil, err)
+ assert.Equal(t, fi.Size(), fi2.Size())
+
+ err = config.Close()
+ assert.Equal(t, nil, err)
+
+ // make log file read-only and check Init returns an error
+ err = os.Chmod(config.FileName, 0444)
+ assert.Equal(t, nil, err)
+ err = config.Init()
+ assert.NotEqual(t, nil, err)
+}
View
3  process.go
@@ -9,7 +9,6 @@ import (
"errors"
"io"
"io/ioutil"
- "log"
"os"
"os/exec"
"os/user"
@@ -206,7 +205,7 @@ func WritePidFile(pid int, path string) error {
// Write pid to Pidfile
func (p *Process) SavePid(pid int) error {
- log.Printf("Saving %q pid to file=%s", p.Name, p.Pidfile)
+ Log.Debugf("Saving %q pid to file=%s", p.Name, p.Pidfile)
return WritePidFile(pid, p.Pidfile)
}
View
2  test/config/gonit.yml
@@ -3,3 +3,5 @@ alerttransport: none
daemon:
name: lolnit
pidfile: /tmp/lolnit.pid
+logging:
+ level: debug
Please sign in to comment.
Something went wrong with that request. Please try again.