Merge lp:~thumper/juju-core/use-loggo into lp:~juju/juju-core/trunk

Proposed by Tim Penhey
Status: Merged
Approved by: William Reade
Approved revision: no longer in the source branch.
Merged at revision: 1250
Proposed branch: lp:~thumper/juju-core/use-loggo
Merge into: lp:~juju/juju-core/trunk
Diff against target: 1039 lines (+177/-249)
19 files modified
charm/dir_test.go (+4/-4)
charm/repo_test.go (+10/-6)
cmd/builddb/main.go (+12/-19)
cmd/charmd/main.go (+0/-3)
cmd/charmload/main.go (+0/-3)
cmd/juju/main_test.go (+8/-2)
cmd/logging.go (+22/-14)
cmd/logging_test.go (+10/-36)
cmd/supercommand_test.go (+1/-7)
environs/cloudinit/cloudinit.go (+2/-2)
log/log.go (+12/-43)
log/log_test.go (+49/-31)
state/watcher/watcher_test.go (+0/-10)
store/store_test.go (+5/-3)
testing/log.go (+19/-8)
worker/uniter/context_test.go (+0/-26)
worker/uniter/jujuc/juju-log_test.go (+16/-30)
worker/uniter/jujuc/server_test.go (+4/-0)
worker/uniter/uniter_test.go (+3/-2)
To merge this branch: bzr merge lp:~thumper/juju-core/use-loggo
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+166611@code.launchpad.net

Description of the change

Integrate loggo as a hierarchical logger.

The existing logging is very flat and has very little control over what is output.

I wrote loggo as a Go port of a C++ library I wrote for nux/unity (my third or fourth logging library). Loggers are very lightweight objects that have a single pointer to the module. A module is defined by a dotted name, like "juju.uniter" or "juju.provider.ec2". There is no limit to the depth of nesting. Logging levels are inherited unless explicitly set. The root logger, identified by the module "" (empty string), defaults to WARNING.

The existing log package has been updated to use the loggo methods so we don't have to change all the call sites immediately. However we should start to move to more detailed modules for logging as we can have better control over it.

We should, as a soon to be done step, provide a way, probably using set-env, to configure logging for various machine agents or unit agents. This would allow a high level of control over what information gets logged.

https://codereview.appspot.com/9738051/

To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :

Reviewers: mp+166611_code.launchpad.net,

Message:
Please take a look.

Description:

https://code.launchpad.net/~thumper/juju-core/use-loggo/+merge/166611

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/9738051/

Affected files:
   A [revision details]
   M charm/dir_test.go
   M charm/repo_test.go
   M cmd/builddb/main.go
   M cmd/charmd/main.go
   M cmd/charmload/main.go
   M cmd/juju/main_test.go
   M cmd/logging.go
   M cmd/logging_test.go
   M cmd/supercommand_test.go
   M environs/cloudinit/cloudinit.go
   M log/log.go
   M log/log_test.go
   M state/watcher/watcher_test.go
   M store/store_test.go
   M testing/log.go
   M worker/uniter/context_test.go
   M worker/uniter/jujuc/juju-log_test.go
   M worker/uniter/jujuc/server_test.go
   M worker/uniter/uniter_test.go

Revision history for this message
Dave Cheney (dave-cheney) wrote :

LGTM.

On Fri, May 31, 2013 at 12:47 PM, Tim Penhey <email address hidden>wrote:

> The proposal to merge lp:~thumper/juju-core/use-loggo into lp:juju-core
> has been updated.
>
> Description changed to:
>
> Integrate loggo as a hierarchical logger.
>
> The existing logging is very flat and has very little control over what is
> output.
>
> I wrote loggo as a Go port of a C++ library I wrote for nux/unity (my
> third or fourth logging library). Loggers are very lightweight objects
> that have a single pointer to the module. A module is defined by a dotted
> name, like "juju.uniter" or "juju.provider.ec2". There is no limit to the
> depth of nesting. Logging levels are inherited unless explicitly set. The
> root logger, identified by the module "" (empty string), defaults to
> WARNING.
>
> The existing log package has been updated to use the loggo methods so we
> don't have to change all the call sites immediately. However we should
> start to move to more detailed modules for logging as we can have better
> control over it.
>
> We should, as a soon to be done step, provide a way, probably using
> set-env, to configure logging for various machine agents or unit agents.
> This would allow a high level of control over what information gets logged.
>
> https://codereview.appspot.com/9738051/
>
> For more details, see:
> https://code.launchpad.net/~thumper/juju-core/use-loggo/+merge/166611
> --
> https://code.launchpad.net/~thumper/juju-core/use-loggo/+merge/166611
> Your team juju hackers is requested to review the proposed merge of
> lp:~thumper/juju-core/use-loggo into lp:juju-core.
>

Revision history for this message
Frank Mueller (themue) wrote :

LGTM

https://codereview.appspot.com/9738051/diff/1/cmd/logging.go
File cmd/logging.go (right):

https://codereview.appspot.com/9738051/diff/1/cmd/logging.go#newcode26
cmd/logging.go:26: // TODO: rename verbose to --show-log
TODO for whom? Use // TODO(nick) ...

https://codereview.appspot.com/9738051/diff/1/worker/uniter/uniter_test.go
File worker/uniter/uniter_test.go (right):

https://codereview.appspot.com/9738051/diff/1/worker/uniter/uniter_test.go#newcode170
worker/uniter/uniter_test.go:170: // TODO: fix this to actually use a
log writer to catch interesting log messages.
Again // TODO(nick) ...

https://codereview.appspot.com/9738051/

Revision history for this message
John A Meinel (jameinel) wrote :

Just to codify it, the switch to loggo LGTM, but I think I uncovered a
couple bugs in loggo itself. (if you do SetLoggingLevel(DEBUG) it
actually doesn't emit logger.Debug() messages (the check is
getEffectiveLevel() > level rather than getEffectiveLevel() >= level).

I'd like us to get some of that sorted out before then.

https://codereview.appspot.com/9738051/

Revision history for this message
Tim Penhey (thumper) wrote :

On 03/06/13 21:21, <email address hidden> wrote:
> Just to codify it, the switch to loggo LGTM, but I think I uncovered a
> couple bugs in loggo itself. (if you do SetLoggingLevel(DEBUG) it
> actually doesn't emit logger.Debug() messages (the check is
> getEffectiveLevel() > level rather than getEffectiveLevel() >= level).

Yes it does, this is just a misunderstanding.

Tests for this are in loggo/writer_test.go

Revision history for this message
John A Meinel (jameinel) wrote :

...

> Yes it does, this is just a misunderstanding.

> Tests for this are in loggo/writer_test.go

Right, I had the comparison turned around. LGTM

https://codereview.appspot.com/9738051/

Revision history for this message
Tim Penhey (thumper) wrote :

*** Submitted:

Integrate loggo as a hierarchical logger.

The existing logging is very flat and has very little control over what
is output.

I wrote loggo as a Go port of a C++ library I wrote for nux/unity (my
third or fourth logging library). Loggers are very lightweight objects
that have a single pointer to the module. A module is defined by a
dotted name, like "juju.uniter" or "juju.provider.ec2". There is no
limit to the depth of nesting. Logging levels are inherited unless
explicitly set. The root logger, identified by the module "" (empty
string), defaults to WARNING.

The existing log package has been updated to use the loggo methods so we
don't have to change all the call sites immediately. However we should
start to move to more detailed modules for logging as we can have better
control over it.

We should, as a soon to be done step, provide a way, probably using
set-env, to configure logging for various machine agents or unit agents.
  This would allow a high level of control over what information gets
logged.

R=mue, jameinel
CC=
https://codereview.appspot.com/9738051

https://codereview.appspot.com/9738051/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charm/dir_test.go'
--- charm/dir_test.go 2013-05-02 15:55:42 +0000
+++ charm/dir_test.go 2013-06-04 23:43:27 +0000
@@ -10,7 +10,6 @@
10 "io/ioutil"10 "io/ioutil"
11 . "launchpad.net/gocheck"11 . "launchpad.net/gocheck"
12 "launchpad.net/juju-core/charm"12 "launchpad.net/juju-core/charm"
13 "launchpad.net/juju-core/log"
14 "launchpad.net/juju-core/testing"13 "launchpad.net/juju-core/testing"
15 "os"14 "os"
16 "path/filepath"15 "path/filepath"
@@ -18,7 +17,9 @@
18 "syscall"17 "syscall"
19)18)
2019
21type DirSuite struct{}20type DirSuite struct {
21 testing.LoggingSuite
22}
2223
23var _ = Suite(&DirSuite{})24var _ = Suite(&DirSuite{})
2425
@@ -121,7 +122,6 @@
121122
122// Bug #864164: Must complain if charm hooks aren't executable123// Bug #864164: Must complain if charm hooks aren't executable
123func (s *DirSuite) TestBundleToWithNonExecutableHooks(c *C) {124func (s *DirSuite) TestBundleToWithNonExecutableHooks(c *C) {
124 defer log.SetTarget(log.SetTarget(c))
125 hooks := []string{"install", "start", "config-changed", "upgrade-charm", "stop"}125 hooks := []string{"install", "start", "config-changed", "upgrade-charm", "stop"}
126 for _, relName := range []string{"foo", "bar", "self"} {126 for _, relName := range []string{"foo", "bar", "self"} {
127 for _, kind := range []string{"joined", "changed", "departed", "broken"} {127 for _, kind := range []string{"joined", "changed", "departed", "broken"} {
@@ -140,7 +140,7 @@
140 tlog := c.GetTestLog()140 tlog := c.GetTestLog()
141 for _, hook := range hooks {141 for _, hook := range hooks {
142 fullpath := filepath.Join(dir.Path, "hooks", hook)142 fullpath := filepath.Join(dir.Path, "hooks", hook)
143 exp := fmt.Sprintf(`^(.|\n)*WARNING charm: making "%s" executable in charm(.|\n)*$`, fullpath)143 exp := fmt.Sprintf(`^(.|\n)*WARNING juju charm: making "%s" executable in charm(.|\n)*$`, fullpath)
144 c.Assert(tlog, Matches, exp, Commentf("hook %q was not made executable", fullpath))144 c.Assert(tlog, Matches, exp, Commentf("hook %q was not made executable", fullpath))
145 }145 }
146146
147147
=== modified file 'charm/repo_test.go'
--- charm/repo_test.go 2013-05-02 15:55:42 +0000
+++ charm/repo_test.go 2013-06-04 23:43:27 +0000
@@ -11,7 +11,6 @@
11 "io/ioutil"11 "io/ioutil"
12 . "launchpad.net/gocheck"12 . "launchpad.net/gocheck"
13 "launchpad.net/juju-core/charm"13 "launchpad.net/juju-core/charm"
14 "launchpad.net/juju-core/log"
15 "launchpad.net/juju-core/testing"14 "launchpad.net/juju-core/testing"
16 "net"15 "net"
17 "net/http"16 "net/http"
@@ -150,6 +149,7 @@
150}149}
151150
152type StoreSuite struct {151type StoreSuite struct {
152 testing.LoggingSuite
153 server *MockStore153 server *MockStore
154 store *charm.CharmStore154 store *charm.CharmStore
155 oldCacheDir string155 oldCacheDir string
@@ -158,19 +158,24 @@
158var _ = Suite(&StoreSuite{})158var _ = Suite(&StoreSuite{})
159159
160func (s *StoreSuite) SetUpSuite(c *C) {160func (s *StoreSuite) SetUpSuite(c *C) {
161 s.LoggingSuite.SetUpSuite(c)
161 s.server = NewMockStore(c)162 s.server = NewMockStore(c)
162 s.oldCacheDir = charm.CacheDir163 s.oldCacheDir = charm.CacheDir
163}164}
164165
165func (s *StoreSuite) SetUpTest(c *C) {166func (s *StoreSuite) SetUpTest(c *C) {
167 s.LoggingSuite.SetUpTest(c)
166 charm.CacheDir = c.MkDir()168 charm.CacheDir = c.MkDir()
167 s.store = charm.NewStore("http://127.0.0.1:4444")169 s.store = charm.NewStore("http://127.0.0.1:4444")
168 s.server.downloads = nil170 s.server.downloads = nil
169}171}
170172
173// Uses the TearDownTest from testing.LoggingSuite
174
171func (s *StoreSuite) TearDownSuite(c *C) {175func (s *StoreSuite) TearDownSuite(c *C) {
172 charm.CacheDir = s.oldCacheDir176 charm.CacheDir = s.oldCacheDir
173 s.server.lis.Close()177 s.server.lis.Close()
178 s.LoggingSuite.TearDownSuite(c)
174}179}
175180
176func (s *StoreSuite) TestMissing(c *C) {181func (s *StoreSuite) TestMissing(c *C) {
@@ -192,9 +197,8 @@
192}197}
193198
194func (s *StoreSuite) TestWarning(c *C) {199func (s *StoreSuite) TestWarning(c *C) {
195 defer log.SetTarget(log.SetTarget(c))
196 curl := charm.MustParseURL("cs:series/unwise")200 curl := charm.MustParseURL("cs:series/unwise")
197 expect := `.* WARNING charm: charm store reports for "cs:series/unwise": foolishness` + "\n"201 expect := `.* WARNING juju charm: charm store reports for "cs:series/unwise": foolishness` + "\n"
198 r, err := s.store.Latest(curl)202 r, err := s.store.Latest(curl)
199 c.Assert(r, Equals, 23)203 c.Assert(r, Equals, 23)
200 c.Assert(err, IsNil)204 c.Assert(err, IsNil)
@@ -495,9 +499,9 @@
495 c.Assert(err, IsNil)499 c.Assert(err, IsNil)
496 c.Assert(ch.Revision(), Equals, 1)500 c.Assert(ch.Revision(), Equals, 1)
497 c.Assert(c.GetTestLog(), Matches, `501 c.Assert(c.GetTestLog(), Matches, `
498.* WARNING charm: failed to load charm at ".*/series/blah": .*502.* WARNING juju charm: failed to load charm at ".*/series/blah": .*
499.* WARNING charm: failed to load charm at ".*/series/blah.charm": .*503.* WARNING juju charm: failed to load charm at ".*/series/blah.charm": .*
500.* WARNING charm: failed to load charm at ".*/series/upgrade2": .*504.* WARNING juju charm: failed to load charm at ".*/series/upgrade2": .*
501`[1:])505`[1:])
502}506}
503507
504508
=== modified file 'cmd/builddb/main.go'
--- cmd/builddb/main.go 2013-05-02 15:55:42 +0000
+++ cmd/builddb/main.go 2013-06-04 23:43:27 +0000
@@ -5,15 +5,15 @@
55
6import (6import (
7 "fmt"7 "fmt"
8 "os"
9 "path/filepath"
10 "time"
11
8 "launchpad.net/juju-core/charm"12 "launchpad.net/juju-core/charm"
9 "launchpad.net/juju-core/environs"13 "launchpad.net/juju-core/environs"
10 "launchpad.net/juju-core/juju"14 "launchpad.net/juju-core/juju"
11 "launchpad.net/juju-core/log"
12 "launchpad.net/juju-core/state/api/params"15 "launchpad.net/juju-core/state/api/params"
13 stdlog "log"16 "launchpad.net/loggo"
14 "os"
15 "path/filepath"
16 "time"
17)17)
1818
19// Import the providers.19// Import the providers.
@@ -21,8 +21,9 @@
21 _ "launchpad.net/juju-core/environs/all"21 _ "launchpad.net/juju-core/environs/all"
22)22)
2323
24var logger = loggo.GetLogger("juju.builddb")
25
24func main() {26func main() {
25 log.SetTarget(stdlog.New(os.Stdout, "", stdlog.LstdFlags))
26 if err := build(); err != nil {27 if err := build(); err != nil {
27 fmt.Fprintf(os.Stderr, "%v\n", err)28 fmt.Fprintf(os.Stderr, "%v\n", err)
28 os.Exit(1)29 os.Exit(1)
@@ -56,13 +57,13 @@
56 return err57 return err
57 }58 }
5859
59 log.Infof("builddb: Waiting for unit to reach %q status...", params.StatusStarted)60 logger.Info("Waiting for unit to reach %q status...", params.StatusStarted)
60 unit := units[0]61 unit := units[0]
61 last, info, err := unit.Status()62 last, info, err := unit.Status()
62 if err != nil {63 if err != nil {
63 return err64 return err
64 }65 }
65 logStatus(last, info)66 logger.Info("Unit status is %q: %s", last, info)
66 for last != params.StatusStarted {67 for last != params.StatusStarted {
67 time.Sleep(2 * time.Second)68 time.Sleep(2 * time.Second)
68 if err := unit.Refresh(); err != nil {69 if err := unit.Refresh(); err != nil {
@@ -73,7 +74,7 @@
73 return err74 return err
74 }75 }
75 if status != last {76 if status != last {
76 logStatus(status, info)77 logger.Info("Unit status is %q: %s", status, info)
77 last = status78 last = status
78 }79 }
79 }80 }
@@ -81,15 +82,7 @@
81 if !ok {82 if !ok {
82 return fmt.Errorf("cannot retrieve files: build unit lacks a public-address")83 return fmt.Errorf("cannot retrieve files: build unit lacks a public-address")
83 }84 }
84 log.Noticef("builddb: Built files published at http://%s", addr)85 logger.Info("Built files published at http://%s", addr)
85 log.Noticef("builddb: Remember to destroy the environment when you're done...")86 logger.Info("Remember to destroy the environment when you're done...")
86 return nil87 return nil
87}88}
88
89func logStatus(status params.Status, info string) {
90 if info == "" {
91 log.Infof("builddb: Unit status is %q", status)
92 } else {
93 log.Infof("builddb: Unit status is %q: %s", status, info)
94 }
95}
9689
=== modified file 'cmd/charmd/main.go'
--- cmd/charmd/main.go 2013-05-02 15:55:42 +0000
+++ cmd/charmd/main.go 2013-06-04 23:43:27 +0000
@@ -7,16 +7,13 @@
7 "fmt"7 "fmt"
8 "io/ioutil"8 "io/ioutil"
9 "launchpad.net/goyaml"9 "launchpad.net/goyaml"
10 "launchpad.net/juju-core/log"
11 "launchpad.net/juju-core/store"10 "launchpad.net/juju-core/store"
12 stdlog "log"
13 "net/http"11 "net/http"
14 "os"12 "os"
15 "path/filepath"13 "path/filepath"
16)14)
1715
18func main() {16func main() {
19 log.SetTarget(stdlog.New(os.Stdout, "", stdlog.LstdFlags))
20 err := serve()17 err := serve()
21 if err != nil {18 if err != nil {
22 fmt.Fprintf(os.Stderr, "%v\n", err)19 fmt.Fprintf(os.Stderr, "%v\n", err)
2320
=== modified file 'cmd/charmload/main.go'
--- cmd/charmload/main.go 2013-05-02 15:55:42 +0000
+++ cmd/charmload/main.go 2013-06-04 23:43:27 +0000
@@ -7,16 +7,13 @@
7 "fmt"7 "fmt"
8 "io/ioutil"8 "io/ioutil"
9 "launchpad.net/goyaml"9 "launchpad.net/goyaml"
10 "launchpad.net/juju-core/log"
11 "launchpad.net/juju-core/store"10 "launchpad.net/juju-core/store"
12 "launchpad.net/lpad"11 "launchpad.net/lpad"
13 stdlog "log"
14 "os"12 "os"
15 "path/filepath"13 "path/filepath"
16)14)
1715
18func main() {16func main() {
19 log.SetTarget(stdlog.New(os.Stdout, "", stdlog.LstdFlags))
20 err := load()17 err := load()
21 if err != nil {18 if err != nil {
22 fmt.Fprintf(os.Stderr, "%v\n", err)19 fmt.Fprintf(os.Stderr, "%v\n", err)
2320
=== modified file 'cmd/juju/main_test.go'
--- cmd/juju/main_test.go 2013-05-28 02:05:06 +0000
+++ cmd/juju/main_test.go 2013-06-04 23:43:27 +0000
@@ -15,6 +15,7 @@
15 _ "launchpad.net/juju-core/environs/dummy"15 _ "launchpad.net/juju-core/environs/dummy"
16 "launchpad.net/juju-core/testing"16 "launchpad.net/juju-core/testing"
17 "launchpad.net/juju-core/version"17 "launchpad.net/juju-core/version"
18 "launchpad.net/loggo"
18 "os"19 "os"
19 "os/exec"20 "os/exec"
20 "path/filepath"21 "path/filepath"
@@ -71,6 +72,10 @@
71 return helpText(&SyncToolsCommand{}, "juju sync-tools")72 return helpText(&SyncToolsCommand{}, "juju sync-tools")
72}73}
7374
75func (s *MainSuite) TestTearDown(c *C) {
76 loggo.ResetLogging()
77}
78
74func (s *MainSuite) TestRunMain(c *C) {79func (s *MainSuite) TestRunMain(c *C) {
75 defer testing.MakeSampleHome(c).Restore()80 defer testing.MakeSampleHome(c).Restore()
76 // The test array structure needs to be inline here as some of the81 // The test array structure needs to be inline here as some of the
@@ -188,7 +193,7 @@
188 c.Assert(out, Equals, "error: "+msg+"\n")193 c.Assert(out, Equals, "error: "+msg+"\n")
189 content, err := ioutil.ReadFile(logpath)194 content, err := ioutil.ReadFile(logpath)
190 c.Assert(err, IsNil)195 c.Assert(err, IsNil)
191 fullmsg := fmt.Sprintf(`(.|\n)*ERROR command failed: %s\n`, msg)196 fullmsg := fmt.Sprintf(`(.|\n)*ERROR .* command failed: %s\n`, msg)
192 c.Assert(string(content), Matches, fullmsg)197 c.Assert(string(content), Matches, fullmsg)
193}198}
194199
@@ -201,7 +206,7 @@
201 c.Assert(out, Equals, "error: "+msg+"\n")206 c.Assert(out, Equals, "error: "+msg+"\n")
202 content, err := ioutil.ReadFile(logpath)207 content, err := ioutil.ReadFile(logpath)
203 c.Assert(err, IsNil)208 c.Assert(err, IsNil)
204 fullmsg := fmt.Sprintf(`(.|\n)*ERROR command failed: %s\n`, msg)209 fullmsg := fmt.Sprintf(`(.|\n)*ERROR .* command failed: %s\n`, msg)
205 c.Assert(string(content), Matches, fullmsg)210 c.Assert(string(content), Matches, fullmsg)
206}211}
207212
@@ -295,6 +300,7 @@
295var globalFlags = []string{300var globalFlags = []string{
296 "--debug .*",301 "--debug .*",
297 "-h, --help .*",302 "-h, --help .*",
303 "--log-config .*",
298 "--log-file .*",304 "--log-file .*",
299 "-v, --verbose .*",305 "-v, --verbose .*",
300}306}
301307
=== modified file 'cmd/logging.go'
--- cmd/logging.go 2013-05-02 15:55:42 +0000
+++ cmd/logging.go 2013-06-04 23:43:27 +0000
@@ -5,10 +5,10 @@
55
6import (6import (
7 "io"7 "io"
8 "os"
9
8 "launchpad.net/gnuflag"10 "launchpad.net/gnuflag"
9 "launchpad.net/juju-core/log"11 "launchpad.net/loggo"
10 stdlog "log"
11 "os"
12)12)
1313
14// Log supplies the necessary functionality for Commands that wish to set up14// Log supplies the necessary functionality for Commands that wish to set up
@@ -17,37 +17,45 @@
17 Path string17 Path string
18 Verbose bool18 Verbose bool
19 Debug bool19 Debug bool
20 log.Logger20 Config string
21}21}
2222
23// AddFlags adds appropriate flags to f.23// AddFlags adds appropriate flags to f.
24func (l *Log) AddFlags(f *gnuflag.FlagSet) {24func (l *Log) AddFlags(f *gnuflag.FlagSet) {
25 f.StringVar(&l.Path, "log-file", "", "path to write log to")25 f.StringVar(&l.Path, "log-file", "", "path to write log to")
26 // TODO: rename verbose to --show-log
26 f.BoolVar(&l.Verbose, "v", false, "if set, log additional messages")27 f.BoolVar(&l.Verbose, "v", false, "if set, log additional messages")
27 f.BoolVar(&l.Verbose, "verbose", false, "if set, log additional messages")28 f.BoolVar(&l.Verbose, "verbose", false, "if set, log additional messages")
28 f.BoolVar(&l.Debug, "debug", false, "if set, log debugging messages")29 f.BoolVar(&l.Debug, "debug", false, "if set, log debugging messages")
29}30 f.StringVar(&l.Config, "log-config", "", "specify log levels for modules")
30
31func (l *Log) Output(calldepth int, s string) error {
32 return l.Logger.Output(calldepth, s)
33}31}
3432
35// Start starts logging using the given Context.33// Start starts logging using the given Context.
36func (l *Log) Start(ctx *Context) (err error) {34func (l *Log) Start(ctx *Context) (err error) {
37 log.Debug = l.Debug
38 var target io.Writer35 var target io.Writer
39 if l.Path != "" {36 if l.Path != "" {
40 path := ctx.AbsPath(l.Path)37 path := ctx.AbsPath(l.Path)
41 target, err = os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)38 target, err = os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
42 if err != nil {39 if err != nil {
43 return40 return err
44 }41 }
45 } else if l.Verbose || l.Debug {42 } else if l.Verbose || l.Debug {
46 target = ctx.Stderr43 target = ctx.Stderr
47 }44 }
45
48 if target != nil {46 if target != nil {
49 l.Logger = stdlog.New(target, "", stdlog.LstdFlags)47 writer := loggo.NewSimpleWriter(target, &loggo.DefaultFormatter{})
50 log.SetTarget(l)48 _, err = loggo.ReplaceDefaultWriter(writer)
51 }49 if err != nil {
52 return50 return err
51 }
52 } else {
53 loggo.RemoveWriter("default")
54 }
55 if l.Debug {
56 logger := loggo.GetLogger("juju")
57 logger.SetLogLevel(loggo.DEBUG)
58 }
59 loggo.ConfigureLogging(l.Config)
60 return nil
53}61}
5462
=== modified file 'cmd/logging_test.go'
--- cmd/logging_test.go 2013-05-02 15:55:42 +0000
+++ cmd/logging_test.go 2013-06-04 23:43:27 +0000
@@ -13,7 +13,6 @@
13)13)
1414
15type LogSuite struct {15type LogSuite struct {
16 testing.LoggingSuite
17}16}
1817
19var _ = Suite(&LogSuite{})18var _ = Suite(&LogSuite{})
@@ -28,53 +27,28 @@
28 c.Assert(l.Path, Equals, "")27 c.Assert(l.Path, Equals, "")
29 c.Assert(l.Verbose, Equals, false)28 c.Assert(l.Verbose, Equals, false)
30 c.Assert(l.Debug, Equals, false)29 c.Assert(l.Debug, Equals, false)
30 c.Assert(l.Config, Equals, "")
3131
32 err = f.Parse(false, []string{"--log-file", "foo", "--verbose", "--debug"})32 err = f.Parse(false, []string{"--log-file", "foo", "--verbose", "--debug",
33 "--log-config=juju.cmd=INFO;juju.worker.deployer=DEBUG"})
33 c.Assert(err, IsNil)34 c.Assert(err, IsNil)
34 c.Assert(l.Path, Equals, "foo")35 c.Assert(l.Path, Equals, "foo")
35 c.Assert(l.Verbose, Equals, true)36 c.Assert(l.Verbose, Equals, true)
36 c.Assert(l.Debug, Equals, true)37 c.Assert(l.Debug, Equals, true)
37}38 c.Assert(l.Config, Equals, "juju.cmd=INFO;juju.worker.deployer=DEBUG")
38
39func (s *LogSuite) TestStart(c *C) {
40 for _, t := range []struct {
41 path string
42 verbose bool
43 debug bool
44 check Checker
45 }{
46 {"", true, true, NotNil},
47 {"", true, false, NotNil},
48 {"", false, true, NotNil},
49 {"", false, false, IsNil},
50 {"foo", true, true, NotNil},
51 {"foo", true, false, NotNil},
52 {"foo", false, true, NotNil},
53 {"foo", false, false, NotNil},
54 } {
55 // commands always start with the log target set to its zero value.
56 log.SetTarget(nil)
57
58 l := &cmd.Log{Path: t.path, Verbose: t.verbose, Debug: t.debug}
59 ctx := testing.Context(c)
60 err := l.Start(ctx)
61 c.Assert(err, IsNil)
62 c.Assert(log.Target(), t.check)
63 c.Assert(log.Debug, Equals, t.debug)
64 }
65}39}
6640
67func (s *LogSuite) TestStderr(c *C) {41func (s *LogSuite) TestStderr(c *C) {
68 l := &cmd.Log{Verbose: true}42 l := &cmd.Log{Verbose: true, Config: "<root>=INFO"}
69 ctx := testing.Context(c)43 ctx := testing.Context(c)
70 err := l.Start(ctx)44 err := l.Start(ctx)
71 c.Assert(err, IsNil)45 c.Assert(err, IsNil)
72 log.Infof("hello")46 log.Infof("hello")
73 c.Assert(bufferString(ctx.Stderr), Matches, `^.* INFO hello\n`)47 c.Assert(bufferString(ctx.Stderr), Matches, `^.* INFO .* hello\n`)
74}48}
7549
76func (s *LogSuite) TestRelPathLog(c *C) {50func (s *LogSuite) TestRelPathLog(c *C) {
77 l := &cmd.Log{Path: "foo.log"}51 l := &cmd.Log{Path: "foo.log", Config: "<root>=INFO"}
78 ctx := testing.Context(c)52 ctx := testing.Context(c)
79 err := l.Start(ctx)53 err := l.Start(ctx)
80 c.Assert(err, IsNil)54 c.Assert(err, IsNil)
@@ -82,12 +56,12 @@
82 c.Assert(bufferString(ctx.Stderr), Equals, "")56 c.Assert(bufferString(ctx.Stderr), Equals, "")
83 content, err := ioutil.ReadFile(filepath.Join(ctx.Dir, "foo.log"))57 content, err := ioutil.ReadFile(filepath.Join(ctx.Dir, "foo.log"))
84 c.Assert(err, IsNil)58 c.Assert(err, IsNil)
85 c.Assert(string(content), Matches, `^.* INFO hello\n`)59 c.Assert(string(content), Matches, `^.* INFO .* hello\n`)
86}60}
8761
88func (s *LogSuite) TestAbsPathLog(c *C) {62func (s *LogSuite) TestAbsPathLog(c *C) {
89 path := filepath.Join(c.MkDir(), "foo.log")63 path := filepath.Join(c.MkDir(), "foo.log")
90 l := &cmd.Log{Path: path}64 l := &cmd.Log{Path: path, Config: "<root>=INFO"}
91 ctx := testing.Context(c)65 ctx := testing.Context(c)
92 err := l.Start(ctx)66 err := l.Start(ctx)
93 c.Assert(err, IsNil)67 c.Assert(err, IsNil)
@@ -95,5 +69,5 @@
95 c.Assert(bufferString(ctx.Stderr), Equals, "")69 c.Assert(bufferString(ctx.Stderr), Equals, "")
96 content, err := ioutil.ReadFile(path)70 content, err := ioutil.ReadFile(path)
97 c.Assert(err, IsNil)71 c.Assert(err, IsNil)
98 c.Assert(string(content), Matches, `^.* INFO hello\n`)72 c.Assert(string(content), Matches, `^.* INFO .* hello\n`)
99}73}
10074
=== modified file 'cmd/supercommand_test.go'
--- cmd/supercommand_test.go 2013-05-21 22:09:29 +0000
+++ cmd/supercommand_test.go 2013-06-04 23:43:27 +0000
@@ -8,7 +8,6 @@
88
9 . "launchpad.net/gocheck"9 . "launchpad.net/gocheck"
10 "launchpad.net/juju-core/cmd"10 "launchpad.net/juju-core/cmd"
11 "launchpad.net/juju-core/log"
12 "launchpad.net/juju-core/testing"11 "launchpad.net/juju-core/testing"
13)12)
1413
@@ -104,17 +103,12 @@
104}103}
105104
106func (s *SuperCommandSuite) TestLogging(c *C) {105func (s *SuperCommandSuite) TestLogging(c *C) {
107 target, debug := log.Target(), log.Debug
108 defer func() {
109 log.SetTarget(target)
110 log.Debug = debug
111 }()
112 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{Name: "jujutest", Log: &cmd.Log{}})106 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{Name: "jujutest", Log: &cmd.Log{}})
113 jc.Register(&TestCommand{Name: "blah"})107 jc.Register(&TestCommand{Name: "blah"})
114 ctx := testing.Context(c)108 ctx := testing.Context(c)
115 code := cmd.Main(jc, ctx, []string{"blah", "--option", "error", "--debug"})109 code := cmd.Main(jc, ctx, []string{"blah", "--option", "error", "--debug"})
116 c.Assert(code, Equals, 1)110 c.Assert(code, Equals, 1)
117 c.Assert(bufferString(ctx.Stderr), Matches, `^.* ERROR command failed: BAM!111 c.Assert(bufferString(ctx.Stderr), Matches, `^.* ERROR .* command failed: BAM!
118error: BAM!112error: BAM!
119`)113`)
120}114}
121115
=== modified file 'environs/cloudinit/cloudinit.go'
--- environs/cloudinit/cloudinit.go 2013-05-31 07:39:15 +0000
+++ environs/cloudinit/cloudinit.go 2013-06-04 23:43:27 +0000
@@ -11,7 +11,6 @@
11 "launchpad.net/juju-core/constraints"11 "launchpad.net/juju-core/constraints"
12 "launchpad.net/juju-core/environs/agent"12 "launchpad.net/juju-core/environs/agent"
13 "launchpad.net/juju-core/environs/config"13 "launchpad.net/juju-core/environs/config"
14 "launchpad.net/juju-core/log"
15 "launchpad.net/juju-core/log/syslog"14 "launchpad.net/juju-core/log/syslog"
16 "launchpad.net/juju-core/state"15 "launchpad.net/juju-core/state"
17 "launchpad.net/juju-core/state/api"16 "launchpad.net/juju-core/state/api"
@@ -131,9 +130,10 @@
131 fmt.Sprintf("echo -n %s > $bin/downloaded-url.txt", shquote(cfg.Tools.URL)),130 fmt.Sprintf("echo -n %s > $bin/downloaded-url.txt", shquote(cfg.Tools.URL)),
132 )131 )
133132
133 // TODO (thumper): work out how to pass the logging config to the children
134 debugFlag := ""134 debugFlag := ""
135 // TODO: disable debug mode by default when the system is stable.135 // TODO: disable debug mode by default when the system is stable.
136 if true || log.Debug {136 if true {
137 debugFlag = " --debug"137 debugFlag = " --debug"
138 }138 }
139139
140140
=== modified file 'log/log.go'
--- log/log.go 2013-05-02 15:55:42 +0000
+++ log/log.go 2013-06-04 23:43:27 +0000
@@ -4,71 +4,40 @@
4package log4package log
55
6import (6import (
7 "fmt"7 "launchpad.net/loggo"
8 "sync"
9)8)
109
11type Logger interface {
12 Output(calldepth int, s string) error
13}
14
15var (10var (
16 target struct {11 logger = loggo.GetLogger("juju")
17 sync.Mutex
18 logger Logger
19 }
20 Debug bool
21)12)
2213
23// Target returns the current log target.
24func Target() Logger {
25 target.Lock()
26 defer target.Unlock()
27 return target.logger
28}
29
30// SetTarget sets the logging target and returns its
31// previous value.
32func SetTarget(logger Logger) (prev Logger) {
33 target.Lock()
34 defer target.Unlock()
35 prev = target.logger
36 target.logger = logger
37 return
38}
39
40func logf(format string, a ...interface{}) error {
41 if target := Target(); target != nil {
42 const calldepth = 3 // magic
43 return target.Output(calldepth, fmt.Sprintf(format, a...))
44 }
45 return nil
46}
47
48// Errorf logs a message using the ERROR priority.14// Errorf logs a message using the ERROR priority.
49func Errorf(format string, a ...interface{}) error {15func Errorf(format string, a ...interface{}) error {
50 return logf("ERROR "+format, a...)16 logger.Log(loggo.ERROR, format, a...)
17 return nil
51}18}
5219
53// Warningf logs a message using the WARNING priority.20// Warningf logs a message using the WARNING priority.
54func Warningf(format string, a ...interface{}) error {21func Warningf(format string, a ...interface{}) error {
55 return logf("WARNING "+format, a...)22 logger.Log(loggo.WARNING, format, a...)
23 return nil
56}24}
5725
58// Noticef logs a message using the NOTICE priority.26// Noticef logs a message using the NOTICE priority.
27// Notice doesn't really convert to the loggo priorities...
59func Noticef(format string, a ...interface{}) error {28func Noticef(format string, a ...interface{}) error {
60 return logf("NOTICE "+format, a...)29 logger.Log(loggo.INFO, format, a...)
30 return nil
61}31}
6232
63// Infof logs a message using the INFO priority.33// Infof logs a message using the INFO priority.
64func Infof(format string, a ...interface{}) error {34func Infof(format string, a ...interface{}) error {
65 return logf("INFO "+format, a...)35 logger.Log(loggo.INFO, format, a...)
36 return nil
66}37}
6738
68// Debugf logs a message using the DEBUG priority.39// Debugf logs a message using the DEBUG priority.
69func Debugf(format string, a ...interface{}) (err error) {40func Debugf(format string, a ...interface{}) (err error) {
70 if Debug {41 logger.Log(loggo.DEBUG, format, a...)
71 return logf("DEBUG "+format, a...)
72 }
73 return nil42 return nil
74}43}
7544
=== modified file 'log/log_test.go'
--- log/log_test.go 2013-05-02 15:55:42 +0000
+++ log/log_test.go 2013-06-04 23:43:27 +0000
@@ -5,61 +5,79 @@
55
6import (6import (
7 "bytes"7 "bytes"
8 "fmt"
9 "testing"
10 "time"
11
8 . "launchpad.net/gocheck"12 . "launchpad.net/gocheck"
9 "launchpad.net/juju-core/log"13 "launchpad.net/juju-core/log"
10 stdlog "log"14 "launchpad.net/loggo"
11 "testing"
12)15)
1316
14func Test(t *testing.T) {17func Test(t *testing.T) {
15 TestingT(t)18 TestingT(t)
16}19}
1720
18type suite struct{}21type testWriter struct {
1922 bytes.Buffer
20var _ = Suite(suite{})23}
2124
22func (suite) TestLoggerDebugFlag(c *C) {25type suite struct {
23 var buf bytes.Buffer26 writer *testWriter
24 defer log.SetTarget(log.SetTarget(stdlog.New(&buf, "JUJU:", 0)))27 oldWriter loggo.Writer
25 log.Debug = false28 oldLevel loggo.Level
29}
30
31var _ = Suite(&suite{})
32
33func (t *testWriter) Write(level loggo.Level, module, filename string, line int, timestamp time.Time, message string) {
34 t.Buffer.WriteString(fmt.Sprintf("%s %s %s", level, module, message))
35}
36
37func (s *suite) SetUpTest(c *C) {
38 var err error
39 s.writer = &testWriter{}
40 s.oldWriter, s.oldLevel, err = loggo.RemoveWriter("default")
41 c.Assert(err, IsNil)
42 err = loggo.RegisterWriter("test", s.writer, loggo.TRACE)
43 c.Assert(err, IsNil)
44 logger := loggo.GetLogger("juju")
45 logger.SetLogLevel(loggo.TRACE)
46}
47
48func (s *suite) TearDownTest(c *C) {
49 _, _, err := loggo.RemoveWriter("test")
50 c.Assert(err, IsNil)
51 err = loggo.RegisterWriter("default", s.oldWriter, s.oldLevel)
52 c.Assert(err, IsNil)
53}
54
55func (s *suite) TestLoggerDebug(c *C) {
26 input := "Hello World"56 input := "Hello World"
27 log.Debugf(input)57 log.Debugf(input)
28 c.Assert(buf.String(), Equals, "")58 c.Assert(s.writer.String(), Equals, "DEBUG juju "+input)
29 buf.Reset()
30 log.Debug = true
31 log.Debugf(input)
32 c.Assert(buf.String(), Equals, "JUJU:DEBUG "+input+"\n")
33}59}
3460
35func (suite) TestInfoLogger(c *C) {61func (s *suite) TestInfoLogger(c *C) {
36 var buf bytes.Buffer
37 defer log.SetTarget(log.SetTarget(stdlog.New(&buf, "JUJU:", 0)))
38 input := "Hello World"62 input := "Hello World"
39 log.Infof(input)63 log.Infof(input)
40 c.Assert(buf.String(), Equals, "JUJU:INFO "+input+"\n")64 c.Assert(s.writer.String(), Equals, "INFO juju "+input)
41}65}
4266
43func (suite) TestErrorLogger(c *C) {67func (s *suite) TestErrorLogger(c *C) {
44 var buf bytes.Buffer
45 defer log.SetTarget(log.SetTarget(stdlog.New(&buf, "JUJU:", 0)))
46 input := "Hello World"68 input := "Hello World"
47 log.Errorf(input)69 log.Errorf(input)
48 c.Assert(buf.String(), Equals, "JUJU:ERROR "+input+"\n")70 c.Assert(s.writer.String(), Equals, "ERROR juju "+input)
49}71}
5072
51func (suite) TestWarningLogger(c *C) {73func (s *suite) TestWarningLogger(c *C) {
52 var buf bytes.Buffer
53 defer log.SetTarget(log.SetTarget(stdlog.New(&buf, "JUJU:", 0)))
54 input := "Hello World"74 input := "Hello World"
55 log.Warningf(input)75 log.Warningf(input)
56 c.Assert(buf.String(), Equals, "JUJU:WARNING "+input+"\n")76 c.Assert(s.writer.String(), Equals, "WARNING juju "+input)
57}77}
5878
59func (suite) TestNoticeLogger(c *C) {79func (s *suite) TestNoticeLogger(c *C) {
60 var buf bytes.Buffer
61 defer log.SetTarget(log.SetTarget(stdlog.New(&buf, "JUJU:", 0)))
62 input := "Hello World"80 input := "Hello World"
63 log.Noticef(input)81 log.Noticef(input)
64 c.Assert(buf.String(), Equals, "JUJU:NOTICE "+input+"\n")82 c.Assert(s.writer.String(), Equals, "INFO juju "+input)
65}83}
6684
=== modified file 'state/watcher/watcher_test.go'
--- state/watcher/watcher_test.go 2013-05-02 15:55:42 +0000
+++ state/watcher/watcher_test.go 2013-06-04 23:43:27 +0000
@@ -7,7 +7,6 @@
7 "labix.org/v2/mgo"7 "labix.org/v2/mgo"
8 "labix.org/v2/mgo/txn"8 "labix.org/v2/mgo/txn"
9 . "launchpad.net/gocheck"9 . "launchpad.net/gocheck"
10 "launchpad.net/juju-core/log"
11 "launchpad.net/juju-core/state/watcher"10 "launchpad.net/juju-core/state/watcher"
12 "launchpad.net/juju-core/testing"11 "launchpad.net/juju-core/testing"
13 "launchpad.net/tomb"12 "launchpad.net/tomb"
@@ -359,15 +358,6 @@
359 const N = 500358 const N = 500
360 const T = 10359 const T = 10
361360
362 // Too much data.. doesn't help.
363 debug := log.Debug
364 defer func() { log.Debug = debug }()
365 log.Debug = false
366 // There is a data race on log.Debug. To avoid this race stop the
367 // watcher before restoring the value of log.Debug so the watcher
368 // does not observe a stale value of log.Debug.
369 defer s.w.Stop()
370
371 c.Logf("Creating %d documents, %d per transaction...", N, T)361 c.Logf("Creating %d documents, %d per transaction...", N, T)
372 ops := make([]txn.Op, T)362 ops := make([]txn.Op, T)
373 for i := 0; i < (N / T); i++ {363 for i := 0; i < (N / T); i++ {
374364
=== modified file 'store/store_test.go'
--- store/store_test.go 2013-05-02 15:55:42 +0000
+++ store/store_test.go 2013-06-04 23:43:27 +0000
@@ -10,7 +10,6 @@
10 "labix.org/v2/mgo/bson"10 "labix.org/v2/mgo/bson"
11 . "launchpad.net/gocheck"11 . "launchpad.net/gocheck"
12 "launchpad.net/juju-core/charm"12 "launchpad.net/juju-core/charm"
13 "launchpad.net/juju-core/log"
14 "launchpad.net/juju-core/store"13 "launchpad.net/juju-core/store"
15 "launchpad.net/juju-core/testing"14 "launchpad.net/juju-core/testing"
16 "strconv"15 "strconv"
@@ -29,6 +28,7 @@
29type StoreSuite struct {28type StoreSuite struct {
30 MgoSuite29 MgoSuite
31 testing.HTTPSuite30 testing.HTTPSuite
31 testing.LoggingSuite
32 store *store.Store32 store *store.Store
33}33}
3434
@@ -37,23 +37,25 @@
37func (s *StoreSuite) SetUpSuite(c *C) {37func (s *StoreSuite) SetUpSuite(c *C) {
38 s.MgoSuite.SetUpSuite(c)38 s.MgoSuite.SetUpSuite(c)
39 s.HTTPSuite.SetUpSuite(c)39 s.HTTPSuite.SetUpSuite(c)
40 s.LoggingSuite.SetUpSuite(c)
40}41}
4142
42func (s *StoreSuite) TearDownSuite(c *C) {43func (s *StoreSuite) TearDownSuite(c *C) {
44 s.LoggingSuite.TearDownSuite(c)
43 s.HTTPSuite.TearDownSuite(c)45 s.HTTPSuite.TearDownSuite(c)
44 s.MgoSuite.TearDownSuite(c)46 s.MgoSuite.TearDownSuite(c)
45}47}
4648
47func (s *StoreSuite) SetUpTest(c *C) {49func (s *StoreSuite) SetUpTest(c *C) {
48 s.MgoSuite.SetUpTest(c)50 s.MgoSuite.SetUpTest(c)
51 s.LoggingSuite.SetUpTest(c)
49 var err error52 var err error
50 s.store, err = store.Open(s.Addr)53 s.store, err = store.Open(s.Addr)
51 c.Assert(err, IsNil)54 c.Assert(err, IsNil)
52 log.SetTarget(c)
53 log.Debug = true
54}55}
5556
56func (s *StoreSuite) TearDownTest(c *C) {57func (s *StoreSuite) TearDownTest(c *C) {
58 s.LoggingSuite.TearDownTest(c)
57 s.HTTPSuite.TearDownTest(c)59 s.HTTPSuite.TearDownTest(c)
58 if s.store != nil {60 if s.store != nil {
59 s.store.Close()61 s.store.Close()
6062
=== modified file 'testing/log.go'
--- testing/log.go 2013-05-02 15:55:42 +0000
+++ testing/log.go 2013-06-04 23:43:27 +0000
@@ -4,8 +4,11 @@
4package testing4package testing
55
6import (6import (
7 "fmt"
8 "time"
9
7 . "launchpad.net/gocheck"10 . "launchpad.net/gocheck"
8 "launchpad.net/juju-core/log"11 "launchpad.net/loggo"
9)12)
1013
11// LoggingSuite redirects the juju logger to the test logger14// LoggingSuite redirects the juju logger to the test logger
@@ -14,18 +17,26 @@
14 restoreLog func()17 restoreLog func()
15}18}
1619
20type gocheckWriter struct {
21 c *C
22}
23
24func (w *gocheckWriter) Write(level loggo.Level, module, filename string, line int, timestamp time.Time, message string) {
25 // Magic calldepth value...
26 w.c.Output(3, fmt.Sprintf("%s %s %s", level, module, message))
27}
28
17func (t *LoggingSuite) SetUpSuite(c *C) {}29func (t *LoggingSuite) SetUpSuite(c *C) {}
18func (t *LoggingSuite) TearDownSuite(c *C) {}30func (t *LoggingSuite) TearDownSuite(c *C) {}
1931
20func (t *LoggingSuite) SetUpTest(c *C) {32func (t *LoggingSuite) SetUpTest(c *C) {
21 target, debug := log.SetTarget(c), log.Debug33 loggo.ResetWriters()
22 t.restoreLog = func() {34 loggo.ReplaceDefaultWriter(&gocheckWriter{c})
23 log.SetTarget(target)35 loggo.ResetLogging()
24 log.Debug = debug36 loggo.GetLogger("juju").SetLogLevel(loggo.DEBUG)
25 }
26 log.Debug = true
27}37}
2838
29func (t *LoggingSuite) TearDownTest(c *C) {39func (t *LoggingSuite) TearDownTest(c *C) {
30 t.restoreLog()40 loggo.ResetLogging()
41 loggo.ResetWriters()
31}42}
3243
=== modified file 'worker/uniter/context_test.go'
--- worker/uniter/context_test.go 2013-05-27 13:16:23 +0000
+++ worker/uniter/context_test.go 2013-06-04 23:43:27 +0000
@@ -8,7 +8,6 @@
8 "io/ioutil"8 "io/ioutil"
9 . "launchpad.net/gocheck"9 . "launchpad.net/gocheck"
10 "launchpad.net/juju-core/juju/testing"10 "launchpad.net/juju-core/juju/testing"
11 "launchpad.net/juju-core/log"
12 "launchpad.net/juju-core/state"11 "launchpad.net/juju-core/state"
13 "launchpad.net/juju-core/utils"12 "launchpad.net/juju-core/utils"
14 "launchpad.net/juju-core/worker/uniter"13 "launchpad.net/juju-core/worker/uniter"
@@ -197,23 +196,7 @@
197 },196 },
198}197}
199198
200type logRecorder struct {
201 c *C
202 prefix string
203 lines []string
204}
205
206func (l *logRecorder) Output(calldepth int, s string) error {
207 if strings.HasPrefix(s, l.prefix) {
208 l.lines = append(l.lines, s[len(l.prefix):])
209 }
210 l.c.Logf("%s", s)
211 return nil
212}
213
214func (s *RunHookSuite) TestRunHook(c *C) {199func (s *RunHookSuite) TestRunHook(c *C) {
215 logger := &logRecorder{c: c, prefix: "INFO worker/uniter: HOOK "}
216 defer log.SetTarget(log.SetTarget(logger))
217 uuid, err := utils.NewUUID()200 uuid, err := utils.NewUUID()
218 c.Assert(err, IsNil)201 c.Assert(err, IsNil)
219 for i, t := range runHookTests {202 for i, t := range runHookTests {
@@ -229,7 +212,6 @@
229 charmDir, outPath = makeCharm(c, spec)212 charmDir, outPath = makeCharm(c, spec)
230 }213 }
231 toolsDir := c.MkDir()214 toolsDir := c.MkDir()
232 logger.lines = nil
233 t0 := time.Now()215 t0 := time.Now()
234 err := ctx.RunHook("something-happened", charmDir, toolsDir, "/path/to/socket")216 err := ctx.RunHook("something-happened", charmDir, toolsDir, "/path/to/socket")
235 if t.err == "" {217 if t.err == "" {
@@ -244,17 +226,9 @@
244 }226 }
245 AssertEnv(c, outPath, charmDir, env, uuid.String())227 AssertEnv(c, outPath, charmDir, env, uuid.String())
246 }228 }
247 var expectLog []string
248 if t.spec.stdout != "" {
249 expectLog = append(expectLog, splitLine(t.spec.stdout)...)
250 }
251 if t.spec.stderr != "" {
252 expectLog = append(expectLog, splitLine(t.spec.stderr)...)
253 }
254 if t.spec.background != "" && time.Now().Sub(t0) > 5*time.Second {229 if t.spec.background != "" && time.Now().Sub(t0) > 5*time.Second {
255 c.Errorf("background process holding up hook execution")230 c.Errorf("background process holding up hook execution")
256 }231 }
257 c.Assert(logger.lines, DeepEquals, expectLog)
258 }232 }
259}233}
260234
261235
=== modified file 'worker/uniter/jujuc/juju-log_test.go'
--- worker/uniter/jujuc/juju-log_test.go 2013-05-02 15:55:42 +0000
+++ worker/uniter/jujuc/juju-log_test.go 2013-06-04 23:43:27 +0000
@@ -4,14 +4,13 @@
4package jujuc_test4package jujuc_test
55
6import (6import (
7 "bytes"
8 "fmt"7 "fmt"
8
9 . "launchpad.net/gocheck"9 . "launchpad.net/gocheck"
10 "launchpad.net/juju-core/cmd"10 "launchpad.net/juju-core/cmd"
11 "launchpad.net/juju-core/log"
12 "launchpad.net/juju-core/testing"11 "launchpad.net/juju-core/testing"
13 "launchpad.net/juju-core/worker/uniter/jujuc"12 "launchpad.net/juju-core/worker/uniter/jujuc"
14 stdlog "log"13 "launchpad.net/loggo"
15)14)
1615
17type JujuLogSuite struct {16type JujuLogSuite struct {
@@ -20,36 +19,27 @@
2019
21var _ = Suite(&JujuLogSuite{})20var _ = Suite(&JujuLogSuite{})
2221
23func pushLog(debug bool) (*bytes.Buffer, func()) {
24 oldTarget, oldDebug := log.Target(), log.Debug
25 var buf bytes.Buffer
26 log.SetTarget(stdlog.New(&buf, "JUJU:", 0))
27 log.Debug = debug
28 return &buf, func() {
29 log.SetTarget(oldTarget)
30 log.Debug = oldDebug
31 }
32}
33
34var commonLogTests = []struct {22var commonLogTests = []struct {
35 debugEnabled bool23 debugFlag bool
36 debugFlag bool24 level loggo.Level
37 target string
38}{25}{
39 {false, false, "JUJU:INFO"},26 {false, loggo.INFO},
40 {false, true, ""},27 {true, loggo.DEBUG},
41 {true, false, "JUJU:INFO"},
42 {true, true, "JUJU:DEBUG"},
43}28}
4429
45func assertLogs(c *C, ctx jujuc.Context, badge string) {30func assertLogs(c *C, ctx jujuc.Context, badge string) {
31 loggo.ConfigureLogging("juju=DEBUG")
32 writer := &loggo.TestWriter{}
33 old_writer, err := loggo.ReplaceDefaultWriter(writer)
34 c.Assert(err, IsNil)
35 defer loggo.ReplaceDefaultWriter(old_writer)
46 msg1 := "the chickens"36 msg1 := "the chickens"
47 msg2 := "are 110% AWESOME"37 msg2 := "are 110% AWESOME"
48 com, err := jujuc.NewCommand(ctx, "juju-log")38 com, err := jujuc.NewCommand(ctx, "juju-log")
49 c.Assert(err, IsNil)39 c.Assert(err, IsNil)
50 for _, t := range commonLogTests {40 for _, t := range commonLogTests {
51 buf, pop := pushLog(t.debugEnabled)41 writer.Clear()
52 defer pop()42 c.Assert(err, IsNil)
5343
54 var args []string44 var args []string
55 if t.debugFlag {45 if t.debugFlag {
@@ -59,13 +49,9 @@
59 }49 }
60 code := cmd.Main(com, &cmd.Context{}, args)50 code := cmd.Main(com, &cmd.Context{}, args)
61 c.Assert(code, Equals, 0)51 c.Assert(code, Equals, 0)
6252 c.Assert(writer.Log, HasLen, 1)
63 if t.target == "" {53 c.Assert(writer.Log[0].Level, Equals, t.level)
64 c.Assert(buf.String(), Equals, "")54 c.Assert(writer.Log[0].Message, Equals, fmt.Sprintf("%s: %s %s", badge, msg1, msg2))
65 } else {
66 expect := fmt.Sprintf("%s %s: %s %s\n", t.target, badge, msg1, msg2)
67 c.Assert(buf.String(), Equals, expect)
68 }
69 }55 }
70}56}
7157
7258
=== modified file 'worker/uniter/jujuc/server_test.go'
--- worker/uniter/jujuc/server_test.go 2013-05-02 15:55:42 +0000
+++ worker/uniter/jujuc/server_test.go 2013-06-04 23:43:27 +0000
@@ -10,6 +10,7 @@
10 "launchpad.net/gnuflag"10 "launchpad.net/gnuflag"
11 . "launchpad.net/gocheck"11 . "launchpad.net/gocheck"
12 "launchpad.net/juju-core/cmd"12 "launchpad.net/juju-core/cmd"
13 "launchpad.net/juju-core/testing"
13 "launchpad.net/juju-core/worker/uniter/jujuc"14 "launchpad.net/juju-core/worker/uniter/jujuc"
14 "net/rpc"15 "net/rpc"
15 "os"16 "os"
@@ -65,6 +66,7 @@
65}66}
6667
67type ServerSuite struct {68type ServerSuite struct {
69 testing.LoggingSuite
68 server *jujuc.Server70 server *jujuc.Server
69 sockPath string71 sockPath string
70 err chan error72 err chan error
@@ -73,6 +75,7 @@
73var _ = Suite(&ServerSuite{})75var _ = Suite(&ServerSuite{})
7476
75func (s *ServerSuite) SetUpTest(c *C) {77func (s *ServerSuite) SetUpTest(c *C) {
78 s.LoggingSuite.SetUpTest(c)
76 s.sockPath = filepath.Join(c.MkDir(), "test.sock")79 s.sockPath = filepath.Join(c.MkDir(), "test.sock")
77 srv, err := jujuc.NewServer(factory, s.sockPath)80 srv, err := jujuc.NewServer(factory, s.sockPath)
78 c.Assert(err, IsNil)81 c.Assert(err, IsNil)
@@ -87,6 +90,7 @@
87 c.Assert(<-s.err, IsNil)90 c.Assert(<-s.err, IsNil)
88 _, err := os.Open(s.sockPath)91 _, err := os.Open(s.sockPath)
89 c.Assert(os.IsNotExist(err), Equals, true)92 c.Assert(os.IsNotExist(err), Equals, true)
93 s.LoggingSuite.TearDownTest(c)
90}94}
9195
92func (s *ServerSuite) Call(c *C, req jujuc.Request) (resp jujuc.Response, err error) {96func (s *ServerSuite) Call(c *C, req jujuc.Request) (resp jujuc.Response, err error) {
9397
=== modified file 'worker/uniter/uniter_test.go'
--- worker/uniter/uniter_test.go 2013-05-31 08:33:34 +0000
+++ worker/uniter/uniter_test.go 2013-06-04 23:43:27 +0000
@@ -168,15 +168,16 @@
168}168}
169169
170func (ctx *context) matchLogHooks(c *C) (match bool, overshoot bool) {170func (ctx *context) matchLogHooks(c *C) (match bool, overshoot bool) {
171 // TODO: fix this to actually use a log writer to catch interesting log messages.
171 // hookPattern matches juju-log calls as generated by writeHook.172 // hookPattern matches juju-log calls as generated by writeHook.
172 hookPattern := fmt.Sprintf(`^.* INFO `+173 hookPattern := fmt.Sprintf(`^.* INFO juju `+
173 `u/0(| [a-z0-9-]+:[0-9]+)`+ // juju-log badge; group matches relation id174 `u/0(| [a-z0-9-]+:[0-9]+)`+ // juju-log badge; group matches relation id
174 `: %s`+ // JUJU_ENV_UUID (context badge; prevents cross-test pollution)175 `: %s`+ // JUJU_ENV_UUID (context badge; prevents cross-test pollution)
175 ` ([0-9a-z-/ ]+)$`, // foo-relation-joined bar/123176 ` ([0-9a-z-/ ]+)$`, // foo-relation-joined bar/123
176 ctx.uuid,177 ctx.uuid,
177 )178 )
178 // donePattern matches uniter logging that indicates a hook has run.179 // donePattern matches uniter logging that indicates a hook has run.
179 donePattern := `^.* (INFO|ERROR) worker/uniter: (ran "[a-z0-9-]+" hook|hook failed)`180 donePattern := `^.* (INFO|ERROR) juju worker/uniter: (ran "[a-z0-9-]+" hook|hook failed)`
180 hookRegexp := regexp.MustCompile(hookPattern)181 hookRegexp := regexp.MustCompile(hookPattern)
181 doneRegexp := regexp.MustCompile(donePattern)182 doneRegexp := regexp.MustCompile(donePattern)
182183

Subscribers

People subscribed via source and target branches