Merge lp:~rogpeppe/juju-core/313-jsoncodec-optional-log into lp:~juju/juju-core/trunk

Proposed by Roger Peppe
Status: Work in progress
Proposed branch: lp:~rogpeppe/juju-core/313-jsoncodec-optional-log
Merge into: lp:~juju/juju-core/trunk
Prerequisite: lp:~rogpeppe/juju-core/312-api-jobs
Diff against target: 326 lines (+145/-30) (has conflicts)
4 files modified
rpc/jsoncodec/codec.go (+31/-17)
rpc/jsoncodec/codec_test.go (+104/-10)
rpc/jsoncodec/conn.go (+2/-3)
state/apiserver/apiserver.go (+8/-0)
Text conflict in cmd/jujud/agent_test.go
Text conflict in cmd/jujud/bootstrap_test.go
Text conflict in environs/agent/agent.go
Contents conflict in state/api/machine.go
Text conflict in state/api/params/params.go
Text conflict in state/apiserver/apiserver.go
Contents conflict in state/apiserver/machine.go
Contents conflict in state/apiserver/machine_test.go
Text conflict in state/apiserver/utils.go
To merge this branch: bzr merge lp:~rogpeppe/juju-core/313-jsoncodec-optional-log
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+165736@code.launchpad.net

Description of the change

rpc/jsoncodec: optional logging

Because we're now using the same codec on
both client and server, we were seeing each message
logged twice when testing. This changes
things so we only log on the server side.

https://codereview.appspot.com/9692044/

To post a comment you must log in.
Revision history for this message
Roger Peppe (rogpeppe) wrote :

Reviewers: mp+165736_code.launchpad.net,

Message:
Please take a look.

Description:
rpc/jsoncodec: optional logging

Because we're now using the same codec on
both client and server, we were seeing each message
logged twice when testing. This changes
things so we only log on the server side.

https://code.launchpad.net/~rogpeppe/juju-core/313-jsoncodec-optional-log/+merge/165736

Requires:
https://code.launchpad.net/~rogpeppe/juju-core/312-api-jobs/+merge/165705

(do not edit description out of merge proposal)

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

Affected files:
   A [revision details]
   M rpc/jsoncodec/codec.go
   M rpc/jsoncodec/codec_test.go
   M rpc/jsoncodec/conn.go
   M state/apiserver/apiserver.go

Revision history for this message
Roger Peppe (rogpeppe) wrote :
Revision history for this message
William Reade (fwereade) wrote :

NOT LGTM I'm afraid.

https://codereview.appspot.com/9692044/diff/5002/rpc/jsoncodec/codec.go
File rpc/jsoncodec/codec.go (right):

https://codereview.appspot.com/9692044/diff/5002/rpc/jsoncodec/codec.go#newcode44
rpc/jsoncodec/codec.go:44: // called before the codec is used for
serving RPC requests.
This is a timebomb that will explode as soon as we have dynamic logging
levels, and someone notices that the API server doesn't respect them. If
you're going to implement this, please do it properly...

https://codereview.appspot.com/9692044/

Revision history for this message
Roger Peppe (rogpeppe) wrote :

Please take a look.

https://codereview.appspot.com/9692044/diff/5002/rpc/jsoncodec/codec.go
File rpc/jsoncodec/codec.go (right):

https://codereview.appspot.com/9692044/diff/5002/rpc/jsoncodec/codec.go#newcode44
rpc/jsoncodec/codec.go:44: // called before the codec is used for
serving RPC requests.
On 2013/05/27 20:29:44, fwereade wrote:
> This is a timebomb that will explode as soon as we have dynamic
logging levels,
> and someone notices that the API server doesn't respect them. If
you're going to
> implement this, please do it properly...

Done.

https://codereview.appspot.com/9692044/

Revision history for this message
William Reade (fwereade) wrote :
Revision history for this message
Ian Booth (wallyworld) wrote :
Revision history for this message
Roger Peppe (rogpeppe) wrote :

On 2013/06/21 01:28:02, wallyworld wrote:
> LGTM

merged as https://codereview.appspot.com/10410046/

https://codereview.appspot.com/9692044/

Unmerged revisions

1243. By Roger Peppe

rpc/jsoncodec: s/LogMessages/SetLogging/

1242. By Roger Peppe

Merged 312-api-jobs into 313-jsoncodec-optional-log.

1241. By Roger Peppe

Merged 312-api-jobs into 313-jsoncodec-optional-log.

1240. By Roger Peppe

rpc/jsoncodec: remove unnecessary logic in test code

1239. By Roger Peppe

rpc/jsoncodec: make log messaging configurable

1238. By Roger Peppe

api: implement Machine.Jobs

1237. By Roger Peppe

merge trunk

1236. By Roger Peppe

cmd/juju: revert bogus change

1235. By Roger Peppe

cmd/jujud: change password for machine agent

1234. By Roger Peppe

gofmt

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'rpc/jsoncodec/codec.go'
--- rpc/jsoncodec/codec.go 2013-05-28 07:01:54 +0000
+++ rpc/jsoncodec/codec.go 2013-06-07 17:45:32 +0000
@@ -8,6 +8,7 @@
8 "launchpad.net/juju-core/log"8 "launchpad.net/juju-core/log"
9 "launchpad.net/juju-core/rpc"9 "launchpad.net/juju-core/rpc"
10 "sync"10 "sync"
11 "sync/atomic"
11)12)
1213
13// JSONConn sends and receives messages to an underlying connection14// JSONConn sends and receives messages to an underlying connection
@@ -20,26 +21,39 @@
20 Close() error21 Close() error
21}22}
2223
23var logRequests = true24// Codec implements rpc.Codec for a connection.
2425type Codec struct {
25// codec implements rpc.Codec for a connection.
26type codec struct {
27 // msg holds the message that's just been read by ReadHeader, so26 // msg holds the message that's just been read by ReadHeader, so
28 // that the body can be read by ReadBody.27 // that the body can be read by ReadBody.
29 msg inMsg28 msg inMsg
30 conn JSONConn29 conn JSONConn
31 mu sync.Mutex30 logMessages int32
32 closing bool31 mu sync.Mutex
32 closing bool
33}33}
3434
35// New returns an rpc codec that uses conn to send and receive35// New returns an rpc codec that uses conn to send and receive
36// messages.36// messages.
37func New(conn JSONConn) rpc.Codec {37func New(conn JSONConn) *Codec {
38 return &codec{38 return &Codec{
39 conn: conn,39 conn: conn,
40 }40 }
41}41}
4242
43// SetLogging sets whether messages will be logged
44// by the codec.
45func (c *Codec) SetLogging(on bool) {
46 val := int32(0)
47 if on {
48 val = 1
49 }
50 atomic.StoreInt32(&c.logMessages, val)
51}
52
53func (c *Codec) isLogging() bool {
54 return atomic.LoadInt32(&c.logMessages) != 0
55}
56
43// inMsg holds an incoming message. We don't know the type of the57// inMsg holds an incoming message. We don't know the type of the
44// parameters or response yet, so we delay parsing by storing them58// parameters or response yet, so we delay parsing by storing them
45// in a RawMessage.59// in a RawMessage.
@@ -66,23 +80,23 @@
66 Response interface{} `json:",omitempty"`80 Response interface{} `json:",omitempty"`
67}81}
6882
69func (c *codec) Close() error {83func (c *Codec) Close() error {
70 c.mu.Lock()84 c.mu.Lock()
71 c.closing = true85 c.closing = true
72 c.mu.Unlock()86 c.mu.Unlock()
73 return c.conn.Close()87 return c.conn.Close()
74}88}
7589
76func (c *codec) isClosing() bool {90func (c *Codec) isClosing() bool {
77 c.mu.Lock()91 c.mu.Lock()
78 defer c.mu.Unlock()92 defer c.mu.Unlock()
79 return c.closing93 return c.closing
80}94}
8195
82func (c *codec) ReadHeader(hdr *rpc.Header) error {96func (c *Codec) ReadHeader(hdr *rpc.Header) error {
83 c.msg = inMsg{} // avoid any potential cross-message contamination.97 c.msg = inMsg{} // avoid any potential cross-message contamination.
84 var err error98 var err error
85 if logRequests {99 if c.isLogging() {
86 var m json.RawMessage100 var m json.RawMessage
87 err = c.conn.Receive(&m)101 err = c.conn.Receive(&m)
88 if err == nil {102 if err == nil {
@@ -111,7 +125,7 @@
111 return nil125 return nil
112}126}
113127
114func (c *codec) ReadBody(body interface{}, isRequest bool) error {128func (c *Codec) ReadBody(body interface{}, isRequest bool) error {
115 if body == nil {129 if body == nil {
116 return nil130 return nil
117 }131 }
@@ -129,7 +143,7 @@
129 return json.Unmarshal(rawBody, body)143 return json.Unmarshal(rawBody, body)
130}144}
131145
132func (c *codec) WriteMessage(hdr *rpc.Header, body interface{}) error {146func (c *Codec) WriteMessage(hdr *rpc.Header, body interface{}) error {
133 r := &outMsg{147 r := &outMsg{
134 RequestId: hdr.RequestId,148 RequestId: hdr.RequestId,
135149
@@ -145,7 +159,7 @@
145 } else {159 } else {
146 r.Response = body160 r.Response = body
147 }161 }
148 if logRequests {162 if c.isLogging() {
149 data, err := json.Marshal(r)163 data, err := json.Marshal(r)
150 if err != nil {164 if err != nil {
151 log.Debugf("rpc/jsoncodec: -> marshal error: %v", err)165 log.Debugf("rpc/jsoncodec: -> marshal error: %v", err)
152166
=== modified file 'rpc/jsoncodec/codec_test.go'
--- rpc/jsoncodec/codec_test.go 2013-05-15 12:34:10 +0000
+++ rpc/jsoncodec/codec_test.go 2013-06-07 17:45:32 +0000
@@ -7,15 +7,19 @@
7 . "launchpad.net/gocheck"7 . "launchpad.net/gocheck"
8 "launchpad.net/juju-core/rpc"8 "launchpad.net/juju-core/rpc"
9 "launchpad.net/juju-core/rpc/jsoncodec"9 "launchpad.net/juju-core/rpc/jsoncodec"
10 "launchpad.net/juju-core/testing"
10 "reflect"11 "reflect"
11 "testing"12 "regexp"
13 stdtesting "testing"
12)14)
1315
14type suite struct{}16type suite struct {
1517 testing.LoggingSuite
16var _ = Suite(suite{})18}
1719
18func TestPackage(t *testing.T) {20var _ = Suite(&suite{})
21
22func TestPackage(t *stdtesting.T) {
19 TestingT(t)23 TestingT(t)
20}24}
2125
@@ -52,7 +56,7 @@
52 expectBody: &value{X: "result"},56 expectBody: &value{X: "result"},
53}}57}}
5458
55func (suite) TestRead(c *C) {59func (*suite) TestRead(c *C) {
56 for i, test := range readTests {60 for i, test := range readTests {
57 c.Logf("test %d", i)61 c.Logf("test %d", i)
58 codec := jsoncodec.New(&testConn{62 codec := jsoncodec.New(&testConn{
@@ -75,7 +79,97 @@
75 }79 }
76}80}
7781
78func (suite) TestErrorAfterClose(c *C) {82func (*suite) TestReadHeaderLogsRequests(c *C) {
83 msg := `{"RequestId":1,"Type": "foo","Id": "id","Request":"frob","Params":{"X":"param"}}`
84 codec := jsoncodec.New(&testConn{
85 readMsgs: []string{msg, msg, msg},
86 })
87 // Check that logging is off by default
88 var h rpc.Header
89 err := codec.ReadHeader(&h)
90 c.Assert(err, IsNil)
91 c.Assert(c.GetTestLog(), Matches, "")
92
93 // Check that we see a log message when we switch logging on.
94 codec.SetLogging(true)
95 err = codec.ReadHeader(&h)
96 c.Assert(err, IsNil)
97 c.Assert(c.GetTestLog(), Matches, ".*DEBUG rpc/jsoncodec: <- "+regexp.QuoteMeta(msg)+`\n`)
98
99 // Check that we can switch it off again
100 codec.SetLogging(false)
101 err = codec.ReadHeader(&h)
102 c.Assert(err, IsNil)
103 c.Assert(c.GetTestLog(), Matches, ".*DEBUG rpc/jsoncodec: <- "+regexp.QuoteMeta(msg)+`\n`)
104}
105
106func (*suite) TestWriteMessageLogsRequests(c *C) {
107 codec := jsoncodec.New(&testConn{})
108 h := rpc.Header{
109 RequestId: 1,
110 Type: "foo",
111 Id: "id",
112 Request: "frob",
113 }
114
115 // Check that logging is off by default
116 err := codec.WriteMessage(&h, value{X: "param"})
117 c.Assert(err, IsNil)
118 c.Assert(c.GetTestLog(), Matches, "")
119
120 // Check that we see a log message when we switch logging on.
121 codec.SetLogging(true)
122 err = codec.WriteMessage(&h, value{X: "param"})
123 c.Assert(err, IsNil)
124 msg := `{"RequestId":1,"Type":"foo","Id":"id","Request":"frob","Params":{"X":"param"}}`
125 c.Assert(c.GetTestLog(), Matches, `.*DEBUG rpc/jsoncodec: -> `+regexp.QuoteMeta(msg)+`\n`)
126
127 // Check that we can switch it off again
128 codec.SetLogging(false)
129 err = codec.WriteMessage(&h, value{X: "param"})
130 c.Assert(err, IsNil)
131 c.Assert(c.GetTestLog(), Matches, `.*DEBUG rpc/jsoncodec: -> `+regexp.QuoteMeta(msg)+`\n`)
132}
133
134func (*suite) TestConcurrentSetLoggingAndWrite(c *C) {
135 // If log messages are not set atomically, this
136 // test will fail when run under the race detector.
137 codec := jsoncodec.New(&testConn{})
138 done := make(chan struct{})
139 go func() {
140 codec.SetLogging(true)
141 done <- struct{}{}
142 }()
143 h := rpc.Header{
144 RequestId: 1,
145 Type: "foo",
146 Id: "id",
147 Request: "frob",
148 }
149 err := codec.WriteMessage(&h, value{X: "param"})
150 c.Assert(err, IsNil)
151 <-done
152}
153
154func (*suite) TestConcurrentSetLoggingAndRead(c *C) {
155 // If log messages are not set atomically, this
156 // test will fail when run under the race detector.
157 msg := `{"RequestId":1,"Type": "foo","Id": "id","Request":"frob","Params":{"X":"param"}}`
158 codec := jsoncodec.New(&testConn{
159 readMsgs: []string{msg, msg, msg},
160 })
161 done := make(chan struct{})
162 go func() {
163 codec.SetLogging(true)
164 done <- struct{}{}
165 }()
166 var h rpc.Header
167 err := codec.ReadHeader(&h)
168 c.Assert(err, IsNil)
169 <-done
170}
171
172func (*suite) TestErrorAfterClose(c *C) {
79 conn := &testConn{173 conn := &testConn{
80 err: errors.New("some error"),174 err: errors.New("some error"),
81 }175 }
@@ -105,7 +199,7 @@
105 Request: "frob",199 Request: "frob",
106 },200 },
107 body: &value{X: "param"},201 body: &value{X: "param"},
108 expect: `{"RequestId": 1, "Type": "foo", "Id": "id", "Request": "frob", "Params": {"X": "param"}}`,202 expect: `{"RequestId": 1, "Type": "foo","Id":"id", "Request": "frob", "Params": {"X": "param"}}`,
109}, {203}, {
110 hdr: &rpc.Header{204 hdr: &rpc.Header{
111 RequestId: 2,205 RequestId: 2,
@@ -121,7 +215,7 @@
121 expect: `{"RequestId": 3, "Response": {"X": "result"}}`,215 expect: `{"RequestId": 3, "Response": {"X": "result"}}`,
122}}216}}
123217
124func (suite) TestWrite(c *C) {218func (*suite) TestWrite(c *C) {
125 for i, test := range writeTests {219 for i, test := range writeTests {
126 c.Logf("test %d", i)220 c.Logf("test %d", i)
127 var conn testConn221 var conn testConn
128222
=== modified file 'rpc/jsoncodec/conn.go'
--- rpc/jsoncodec/conn.go 2013-05-16 17:31:36 +0000
+++ rpc/jsoncodec/conn.go 2013-06-07 17:45:32 +0000
@@ -3,13 +3,12 @@
3import (3import (
4 "code.google.com/p/go.net/websocket"4 "code.google.com/p/go.net/websocket"
5 "encoding/json"5 "encoding/json"
6 "launchpad.net/juju-core/rpc"
7 "net"6 "net"
8)7)
98
10// NewWebsocket returns an rpc codec that uses the given websocket9// NewWebsocket returns an rpc codec that uses the given websocket
11// connection to send and receive messages.10// connection to send and receive messages.
12func NewWebsocket(conn *websocket.Conn) rpc.Codec {11func NewWebsocket(conn *websocket.Conn) *Codec {
13 return New(wsJSONConn{conn})12 return New(wsJSONConn{conn})
14}13}
1514
@@ -31,7 +30,7 @@
3130
32// NewNet returns an rpc codec that uses the given net31// NewNet returns an rpc codec that uses the given net
33// connection to send and receive messages.32// connection to send and receive messages.
34func NewNet(conn net.Conn) rpc.Codec {33func NewNet(conn net.Conn) *Codec {
35 return New(&netConn{34 return New(&netConn{
36 enc: json.NewEncoder(conn),35 enc: json.NewEncoder(conn),
37 dec: json.NewDecoder(conn),36 dec: json.NewDecoder(conn),
3837
=== modified file 'state/apiserver/apiserver.go'
--- state/apiserver/apiserver.go 2013-06-06 17:09:49 +0000
+++ state/apiserver/apiserver.go 2013-06-07 17:45:32 +0000
@@ -96,6 +96,7 @@
96}96}
9797
98func (srv *Server) serveConn(wsConn *websocket.Conn) error {98func (srv *Server) serveConn(wsConn *websocket.Conn) error {
99<<<<<<< TREE
99 conn := rpc.NewConn(jsoncodec.NewWebsocket(wsConn))100 conn := rpc.NewConn(jsoncodec.NewWebsocket(wsConn))
100 serverError := func(err error) error {101 serverError := func(err error) error {
101 if err := common.ServerError(err); err != nil {102 if err := common.ServerError(err); err != nil {
@@ -103,6 +104,13 @@
103 }104 }
104 return nil105 return nil
105 }106 }
107=======
108 codec := jsoncodec.NewWebsocket(wsConn)
109 if log.Debug {
110 codec.SetLogging(true)
111 }
112 conn := rpc.NewConn(codec)
113>>>>>>> MERGE-SOURCE
106 if err := conn.Serve(newStateServer(srv), serverError); err != nil {114 if err := conn.Serve(newStateServer(srv), serverError); err != nil {
107 return err115 return err
108 }116 }

Subscribers

People subscribed via source and target branches